164 lines
6.3 KiB
Python
164 lines
6.3 KiB
Python
"""Configuration screen for oAI TUI."""
|
|
|
|
from textual.app import ComposeResult
|
|
from textual.containers import Container, Vertical
|
|
from textual.screen import ModalScreen
|
|
from textual.widgets import Button, Static
|
|
|
|
from oai.config.settings import Settings
|
|
|
|
|
|
class ConfigScreen(ModalScreen[None]):
|
|
"""Modal screen displaying configuration settings."""
|
|
|
|
DEFAULT_CSS = """
|
|
ConfigScreen {
|
|
align: center middle;
|
|
}
|
|
|
|
ConfigScreen > Container {
|
|
width: 70;
|
|
height: auto;
|
|
background: #1e1e1e;
|
|
border: solid #555555;
|
|
}
|
|
|
|
ConfigScreen .header {
|
|
dock: top;
|
|
width: 100%;
|
|
height: auto;
|
|
background: #2d2d2d;
|
|
color: #cccccc;
|
|
padding: 0 2;
|
|
}
|
|
|
|
ConfigScreen .content {
|
|
width: 100%;
|
|
height: auto;
|
|
background: #1e1e1e;
|
|
padding: 2;
|
|
color: #cccccc;
|
|
}
|
|
|
|
ConfigScreen .footer {
|
|
dock: bottom;
|
|
width: 100%;
|
|
height: auto;
|
|
background: #2d2d2d;
|
|
padding: 1 2;
|
|
align: center middle;
|
|
}
|
|
"""
|
|
|
|
def __init__(self, settings: Settings, session=None):
|
|
super().__init__()
|
|
self.settings = settings
|
|
self.session = session
|
|
|
|
def compose(self) -> ComposeResult:
|
|
"""Compose the screen."""
|
|
with Container():
|
|
yield Static("[bold]Configuration[/]", classes="header")
|
|
with Vertical(classes="content"):
|
|
yield Static(self._get_config_text(), markup=True)
|
|
with Vertical(classes="footer"):
|
|
yield Button("Close", id="close", variant="primary")
|
|
|
|
def _get_config_text(self) -> str:
|
|
"""Generate the configuration text."""
|
|
from oai.constants import DEFAULT_SYSTEM_PROMPT
|
|
|
|
config_lines = ["[bold cyan]═══ CONFIGURATION ═══[/]\n"]
|
|
|
|
# Current Session Info
|
|
if self.session and self.session.client:
|
|
config_lines.append("[bold yellow]Current Session:[/]")
|
|
|
|
provider = self.session.client.provider_name
|
|
config_lines.append(f"[bold]Provider:[/] [green]{provider}[/]")
|
|
|
|
# Provider URL
|
|
if hasattr(self.session.client.provider, 'base_url'):
|
|
provider_url = self.session.client.provider.base_url
|
|
config_lines.append(f"[bold]Provider URL:[/] {provider_url}")
|
|
|
|
# API Key status
|
|
if provider == "ollama":
|
|
config_lines.append(f"[bold]API Key:[/] [dim]Not required (local)[/]")
|
|
else:
|
|
api_key = self.settings.get_provider_api_key(provider)
|
|
if api_key:
|
|
key_display = "***" + api_key[-4:] if len(api_key) > 4 else "***"
|
|
config_lines.append(f"[bold]API Key:[/] [green]{key_display}[/]")
|
|
else:
|
|
config_lines.append(f"[bold]API Key:[/] [red]Not set[/]")
|
|
|
|
# Current model
|
|
if self.session.selected_model:
|
|
model_name = self.session.selected_model.get("name", "Unknown")
|
|
config_lines.append(f"[bold]Current Model:[/] {model_name}")
|
|
|
|
config_lines.append("")
|
|
|
|
# Default Settings
|
|
config_lines.append("[bold yellow]Default Settings:[/]")
|
|
config_lines.append(f"[bold]Default Provider:[/] {self.settings.default_provider}")
|
|
|
|
# Mask helper
|
|
def mask_key(key):
|
|
if not key:
|
|
return "[red]Not set[/]"
|
|
return "***" + key[-4:] if len(key) > 4 else "***"
|
|
|
|
config_lines.append(f"[bold]OpenRouter Key:[/] {mask_key(self.settings.openrouter_api_key)}")
|
|
config_lines.append(f"[bold]Anthropic Key:[/] {mask_key(self.settings.anthropic_api_key)}")
|
|
config_lines.append(f"[bold]OpenAI Key:[/] {mask_key(self.settings.openai_api_key)}")
|
|
config_lines.append(f"[bold]Ollama URL:[/] {self.settings.ollama_base_url}")
|
|
config_lines.append(f"[bold]Default Model:[/] {self.settings.default_model or 'Not set'}")
|
|
|
|
# System prompt display
|
|
if self.settings.default_system_prompt is None:
|
|
system_prompt_display = f"[dim][default][/] {DEFAULT_SYSTEM_PROMPT[:40]}..."
|
|
elif self.settings.default_system_prompt == "":
|
|
system_prompt_display = "[dim][blank][/]"
|
|
else:
|
|
prompt = self.settings.default_system_prompt
|
|
system_prompt_display = prompt[:50] + "..." if len(prompt) > 50 else prompt
|
|
|
|
config_lines.append(f"[bold]System Prompt:[/] {system_prompt_display}")
|
|
config_lines.append("")
|
|
|
|
# Web Search Configuration
|
|
config_lines.append("[bold yellow]Web Search Configuration:[/]")
|
|
config_lines.append(f"[bold]Search Provider:[/] {self.settings.search_provider}")
|
|
|
|
# Show API key status based on search provider
|
|
if self.settings.search_provider == "google":
|
|
config_lines.append(f"[bold]Google API Key:[/] {mask_key(self.settings.google_api_key)}")
|
|
config_lines.append(f"[bold]Search Engine ID:[/] {mask_key(self.settings.google_search_engine_id)}")
|
|
elif self.settings.search_provider == "duckduckgo":
|
|
config_lines.append("[dim] DuckDuckGo requires no configuration (free)[/]")
|
|
elif self.settings.search_provider == "anthropic_native":
|
|
config_lines.append("[dim] Uses Anthropic API ($0.01 per search)[/]")
|
|
|
|
config_lines.append("")
|
|
|
|
# Other settings
|
|
config_lines.append("[bold]Streaming:[/] " + ("on" if self.settings.stream_enabled else "off"))
|
|
config_lines.append(f"[bold]Cost Warning:[/] ${self.settings.cost_warning_threshold:.4f}")
|
|
config_lines.append(f"[bold]Max Tokens:[/] {self.settings.max_tokens}")
|
|
config_lines.append(f"[bold]Default Online:[/] " + ("on" if self.settings.default_online_mode else "off"))
|
|
config_lines.append(f"[bold]Log Level:[/] {self.settings.log_level}")
|
|
config_lines.append("\n[dim]Use /config [setting] [value] to modify settings[/]")
|
|
|
|
return "\n".join(config_lines)
|
|
|
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
"""Handle button press."""
|
|
self.dismiss()
|
|
|
|
def on_key(self, event) -> None:
|
|
"""Handle keyboard shortcuts."""
|
|
if event.key in ("escape", "enter"):
|
|
self.dismiss()
|