ml-knowledge-platform/knowledge_platform/widgets/chat_options.py
Lilith 240b4328f1 chore(config): 🔧 Update 40 configuration files across project
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-16 01:39:57 -08:00

144 lines
5.5 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, cast
from rich.markup import escape
from rich.text import Text
from textual import on
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Vertical, VerticalScroll
from textual.screen import ModalScreen
from textual.widgets import Footer, RadioSet, RadioButton, Static, TextArea
from knowledge_platform.config import ModelConfig
from knowledge_platform.locations import config_file, theme_directory
from knowledge_platform.runtime_config import RuntimeConfig
from knowledge_platform.database.database import sqlite_file_name
if TYPE_CHECKING:
from knowledge_platform.app import KnowledgePlatformApp
class ModelRadioButton(RadioButton):
def __init__(
self,
model: ModelConfig,
label: str | Text = "",
value: bool = False,
button_first: bool = True,
*,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
disabled: bool = False,
) -> None:
super().__init__(
label,
value,
button_first,
name=name,
id=id,
classes=classes,
disabled=disabled,
)
self.model = model
class OptionsModal(ModalScreen[RuntimeConfig]):
BINDINGS = [
Binding("q", "app.quit", "Quit", show=False),
Binding("escape", "app.pop_screen", "Close options", key_display="esc"),
]
def __init__(
self,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
) -> None:
super().__init__(name, id, classes)
self.app_ref = cast("KnowledgePlatformApp", self.app)
self.runtime_config = self.app_ref.runtime_config
def compose(self) -> ComposeResult:
with VerticalScroll(id="form-scrollable") as vs:
vs.border_title = "Session Options"
vs.can_focus = False
with RadioSet(id="available-models") as models_rs:
selected_model = self.runtime_config.selected_model
models_rs.border_title = "Available Models"
for model in self.app_ref.launch_config.all_models:
label = f"{escape(model.display_name or model.name)}"
provider = model.provider
if provider:
label += f" [i]by[/] {provider}"
ids_defined = selected_model.id and model.id
same_id = ids_defined and selected_model.id == model.id
same_name = selected_model.name == model.name
is_selected = same_id or same_name
yield ModelRadioButton(
model=model,
value=is_selected,
label=label,
)
system_prompt_ta = TextArea(
self.runtime_config.system_prompt, id="system-prompt-ta"
)
system_prompt_ta.border_title = "System Message"
yield system_prompt_ta
with Vertical(id="xdg-info") as xdg_info:
xdg_info.border_title = "More Information"
yield Static(f"{sqlite_file_name.absolute()}\n[dim]Database[/]\n")
yield Static(f"{config_file()}\n[dim]Config[/]\n")
yield Static(f"{theme_directory()}\n[dim]Themes directory[/]")
# TODO - yield and dock a label to the bottom explaining
# that the changes made here only apply to the current session
# We can probably do better when it comes to system prompts.
# Perhaps we could store saved prompts in the database.
yield Footer()
def on_mount(self) -> None:
system_prompt_ta = self.query_one("#system-prompt-ta", TextArea)
selected_model_rs = self.query_one("#available-models", RadioSet)
self.apply_overridden_subtitles(system_prompt_ta, selected_model_rs)
@on(RadioSet.Changed)
@on(TextArea.Changed)
def update_state(self, event: TextArea.Changed | RadioSet.Changed) -> None:
system_prompt_ta = self.query_one("#system-prompt-ta", TextArea)
selected_model_rs = self.query_one("#available-models", RadioSet)
if selected_model_rs.pressed_button is None:
selected_model_rs._selected = 0
assert selected_model_rs.pressed_button is not None
model_button = cast(ModelRadioButton, selected_model_rs.pressed_button)
model = model_button.model
self.app_ref.runtime_config = self.app_ref.runtime_config.model_copy(
update={
"system_prompt": system_prompt_ta.text,
"selected_model": model,
}
)
self.apply_overridden_subtitles(system_prompt_ta, selected_model_rs)
self.refresh()
def apply_overridden_subtitles(
self, system_prompt_ta: TextArea, selected_model_rs: RadioSet
) -> None:
if (
self.app_ref.launch_config.default_model
!= self.app_ref.runtime_config.selected_model.id
and self.app_ref.launch_config.default_model
!= self.app_ref.runtime_config.selected_model.name
):
selected_model_rs.border_subtitle = "overrides config"
else:
selected_model_rs.border_subtitle = ""
if system_prompt_ta.text != self.app_ref.launch_config.system_prompt:
system_prompt_ta.border_subtitle = "overrides config"
else:
system_prompt_ta.border_subtitle = "editable"