Files
oai/oai/tui/screens/config_screen.py

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()