Files
mitus/cht/ui/agent_input.py

126 lines
4.5 KiB
Python

"""Agent input panel — entry, action buttons, model/language dropdowns."""
import logging
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, GObject
from cht.agent.runner import ACTIONS
from cht.transcriber.engine import LANGUAGES
log = logging.getLogger(__name__)
class AgentInputPanel(Gtk.Frame):
"""Input bar with action buttons, model/lang selectors, and text entry."""
__gsignals__ = {
"send-requested": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
"action-requested": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
"model-changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
"lang-changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
"history-toggled": (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
}
def __init__(self, **kwargs):
super().__init__(**kwargs)
outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
outer.set_margin_start(4)
outer.set_margin_end(4)
outer.set_margin_top(4)
outer.set_margin_bottom(4)
actions_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
for label, verb in ACTIONS.items():
btn = Gtk.Button(label=label)
btn.add_css_class("flat")
btn.connect("clicked", lambda b, v=verb: self.emit("action-requested", v))
actions_box.append(btn)
spacer = Gtk.Box()
spacer.set_hexpand(True)
actions_box.append(spacer)
model_label = Gtk.Label(label="Model:")
model_label.add_css_class("dim-label")
actions_box.append(model_label)
self._model_dropdown = Gtk.DropDown.new_from_strings([])
self._model_dropdown.set_size_request(200, -1)
self._model_dropdown.connect("notify::selected", self._on_model_changed)
actions_box.append(self._model_dropdown)
lang_label = Gtk.Label(label="Lang:")
lang_label.add_css_class("dim-label")
actions_box.append(lang_label)
lang_names = list(LANGUAGES.keys())
self._lang_names = lang_names
self._lang_dropdown = Gtk.DropDown.new_from_strings(lang_names)
self._lang_dropdown.set_selected(0)
self._lang_dropdown.connect("notify::selected", self._on_lang_changed)
actions_box.append(self._lang_dropdown)
history_toggle = Gtk.CheckButton(label="Chat")
history_toggle.set_tooltip_text("Include conversation history in prompts")
history_toggle.connect("toggled", lambda b: self.emit("history-toggled", b.get_active()))
actions_box.append(history_toggle)
outer.append(actions_box)
input_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
self._entry = Gtk.Entry()
self._entry.set_hexpand(True)
self._entry.set_placeholder_text("Message agent... (@F1-3 frames, @T1-5 transcript)")
self._entry.connect("activate", lambda e: self._do_send())
input_row.append(self._entry)
send_btn = Gtk.Button(label="Send")
send_btn.add_css_class("suggested-action")
send_btn.connect("clicked", lambda b: self._do_send())
input_row.append(send_btn)
outer.append(input_row)
self.set_child(outer)
@property
def entry(self) -> Gtk.Entry:
"""The text entry widget (for focus checks)."""
return self._entry
def get_text(self) -> str:
return self._entry.get_text().strip()
def clear_text(self) -> None:
self._entry.set_text("")
def populate_models(self, models: list[str], current: str | None = None) -> None:
if not models:
return
string_list = Gtk.StringList.new(models)
self._model_dropdown.set_model(string_list)
if current:
for i, m in enumerate(models):
if m == current:
self._model_dropdown.set_selected(i)
break
def _do_send(self):
text = self.get_text()
self.clear_text()
self.emit("send-requested", text)
def _on_model_changed(self, dropdown, _pspec):
idx = dropdown.get_selected()
model = dropdown.get_model()
if model and idx < model.get_n_items():
self.emit("model-changed", model.get_string(idx))
def _on_lang_changed(self, dropdown, _pspec):
idx = dropdown.get_selected()
if idx < len(self._lang_names):
lang_code = LANGUAGES[self._lang_names[idx]]
self.emit("lang-changed", lang_code or "")