From d663d2dbd85776bd52c3e62887137b178c360e1c Mon Sep 17 00:00:00 2001 From: Dita Aji Pratama Date: Tue, 8 Sep 2026 11:23:14 +0700 Subject: [PATCH] Improve Model Option --- interfaces/tui/app.py | 26 ++++++++------- interfaces/tui/moopui.py | 68 +++++++++++++++++++++++++++++++++------- services/llm_client.py | 22 +++++++++++++ 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/interfaces/tui/app.py b/interfaces/tui/app.py index b0ca2a9..58e0ebd 100644 --- a/interfaces/tui/app.py +++ b/interfaces/tui/app.py @@ -76,8 +76,7 @@ class HendrikTUI: except Exception: return "-" - def switch_model_set(self, set_id): - default_chain = moop.default_chain(None, "llm") + def switch_model_set(self, set_id, type_name="llm"): target = moop.get_set(None, set_id) if not target: return @@ -85,17 +84,22 @@ class HendrikTUI: if not chain: log(self, "error", "Model set tidak memiliki model yang aktif.") return - if not default_chain: - moop.set_default(None, "llm", set_id) - self.llm.set_chains({"llm": chain}) - self.model_set_name = target.get("name") or self._lookup_model_set_name() - if self.current_session: - self.session_mgr.update_model_info( - self.current_session.doc_id, self._model_info() - ) + + moop.set_default(None, type_name, set_id) + + if type_name in ("llm", "imagevision"): + self.llm.set_type_chain(type_name, chain) + if self.current_session: + self.session_mgr.update_model_info( + self.current_session.doc_id, self._model_info() + ) + + if type_name == "llm": + self.model_set_name = target.get("name") or self._lookup_model_set_name() + candidate = chain[0] log(self, "system", - f"Model \u2192 {candidate['provider']} / {candidate['model']}") + f"[{type_name}] Model \u2192 {candidate['provider']} / {candidate['model']}") def _model_info(self) -> dict: return { diff --git a/interfaces/tui/moopui.py b/interfaces/tui/moopui.py index c457166..48df60a 100644 --- a/interfaces/tui/moopui.py +++ b/interfaces/tui/moopui.py @@ -243,46 +243,92 @@ def _first_model_desc(set_id): # ---------------------------------------------------------- select model --- -def model_selector_popup(app, stdscr): +_TYPE_LABELS = { + "llm": "LLM", + "embedding": "Embedding", + "imagegen": "Image Generation", + "imagevision": "Image Vision", +} + + +def _type_active_desc(type_name): + """Deskripsi 'set [model]' yang sedang aktif untuk satu tipe.""" + default_id = moop.get_default_set_id(None, type_name) + if not default_id: + return None + s = moop.get_set(None, default_id) + if not s: + return None + desc = s["name"] or "-" + model = _first_model_desc(default_id) + if model: + desc += f" [{model}]" + return desc + + +def _pick_set_for_type(app, stdscr, type_name): + """Pilih model set yang menjadi default untuk satu tipe.""" + label = _TYPE_LABELS.get(type_name, type_name) while True: sets = moop.list_sets(None) ids = [] items = [] flags = [] current = 0 - default_id = moop.get_default_set_id(None, "llm") + default_id = moop.get_default_set_id(None, type_name) for s in sets: - if "llm" not in s["types"]: + if type_name not in s["types"]: continue ids.append(s["id"]) - label = s["name"] + row = s["name"] if s["id"] == default_id: - label += " [default]" + row += " [default]" first = _first_model_desc(s["id"]) if first: - label += f" ({first})" - items.append(label) + row += f" ({first})" + items.append(row) flags.append(s["id"] == default_id) if s["id"] == default_id: current = len(items) - 1 if not items: - log(app, "error", "Tidak ada model set tipe 'llm'. Atur via Model > Manage Sets.") + if _confirm(app, stdscr, + f"Belum ada model set tipe '{label}'. Buka Model > Manage Sets?"): + sets_manage_popup(app, stdscr) return idx, key = _run_list_popup( - app, stdscr, "Pilih Model Set (LLM)", items, - footer=" \u2191\u2193 nav \u21b5 select esc close ", + app, stdscr, f"Pilih Model Set ({label})", items, + footer=" \u2191\u2193 nav \u21b5 select esc back ", current_idx=current, active_flags=flags, ) if key == 27: return elif key in (10, 13, curses.KEY_ENTER): - app.switch_model_set(ids[idx]) + app.switch_model_set(ids[idx], type_name) return +def model_selector_popup(app, stdscr): + while True: + items = [] + types = [] + for t in MODEL_TYPES: + types.append(t) + active = _type_active_desc(t) + items.append(f"{_TYPE_LABELS.get(t, t)} \u2192 {active or '-'}") + + idx, key = _run_list_popup( + app, stdscr, "Pilih Tipe Model Set", items, + footer=" \u2191\u2193 nav \u21b5 pilih esc close ", + ) + if key == 27: + return + elif key in (10, 13, curses.KEY_ENTER): + _pick_set_for_type(app, stdscr, types[idx]) + + # ------------------------------------------------------------ manage sets --- def sets_manage_popup(app, stdscr): diff --git a/services/llm_client.py b/services/llm_client.py index 9971ebd..e2c1ab4 100644 --- a/services/llm_client.py +++ b/services/llm_client.py @@ -58,6 +58,28 @@ class LLMClient: self.model = "" self.api_key = "" + def set_type_chain(self, type_name, chain): + """Perbarui satu tipe chain tanpa menimpa tipe lain. + + Setelah update, kandidat pertama chain 'llm' kembali diterapkan + ke base_url/model/api_key aktif (jika ada).""" + chains = dict(self._chains or {}) + chains[type_name] = chain or [] + self._chains = chains + self._chain = None + self._chain_key = None + self._chain_index = 0 + llm = self._chains.get("llm") or [] + vision = self._chains.get("imagevision") or [] + if llm: + self._apply_candidate(llm[0]) + elif vision: + self._apply_candidate(vision[0]) + else: + self.base_url = "" + self.model = "" + self.api_key = "" + def has_chain(self, type_name="llm"): return bool(self._chains.get(type_name))