amplegest / dashboard /model_picker.py
Viney's picture
feat: multi-provider LLM support, prominent chat, design pass, and new analytics
7880373
Raw
History Blame Contribute Delete
3.35 kB
"""dashboard/model_picker.py β€” sidebar provider/model/API-key picker.
Renders a compact popover in the sidebar showing the active provider+model,
and lets the visitor paste their own API key for this browser session only.
Returns a frozen ``RunConfig`` (or None when no key is available) that the
caller threads through to generation / chat / translation β€” never re-read
from session_state after the click that consumes it.
"""
from __future__ import annotations
import streamlit as st
from agent.llm import (
MODEL_CATALOG,
PROVIDER_LABELS,
RunConfig,
console_url,
key_looks_valid,
resolve_api_key,
)
from dashboard.i18n import t
def render() -> tuple[RunConfig | None, str]:
"""Render the Model popover. Returns (config, key_source).
config is None when no key is available anywhere (env or pasted) β€”
callers must block the action (Generate / chat) in that case.
"""
st.session_state.setdefault("llm_provider", "anthropic")
provider = st.session_state["llm_provider"]
default_model = MODEL_CATALOG[provider][0][0]
model_key = f"llm_model_{provider}"
st.session_state.setdefault(model_key, default_model)
active_model = st.session_state[model_key]
active_label = next(
(label for mid, label in MODEL_CATALOG[provider] if mid == active_model),
active_model,
)
short_label = active_label.split(" β€” ")[0]
with st.popover(f"βš™ {PROVIDER_LABELS[provider]} Β· {short_label}", use_container_width=True):
st.caption(t("model_settings_title"))
selected_provider = st.radio(
t("model_provider_label"),
options=list(MODEL_CATALOG.keys()),
format_func=lambda p: PROVIDER_LABELS.get(p, p),
key="llm_provider",
horizontal=True,
)
model_options = MODEL_CATALOG[selected_provider]
model_ids = [mid for mid, _label in model_options]
model_key = f"llm_model_{selected_provider}"
st.session_state.setdefault(model_key, model_options[0][0])
selected_model = st.selectbox(
t("model_select_label"),
options=model_ids,
format_func=lambda mid: next((lbl for m, lbl in model_options if m == mid), mid),
key=model_key,
)
key_state_key = f"llm_api_key_{selected_provider}"
user_key = st.text_input(
t("model_key_label"),
type="password",
key=key_state_key,
help=t("model_key_help"),
)
if user_key and not key_looks_valid(selected_provider, user_key):
st.caption(
"⚠ " + t("model_key_prefix_warning").format(
provider=PROVIDER_LABELS.get(selected_provider, selected_provider)
)
)
key, source = resolve_api_key(selected_provider, user_key)
if source == "env":
st.caption(t("model_status_env"))
elif source == "user":
st.caption(t("model_status_user"))
else:
st.warning(
t("model_status_missing").format(url=console_url(selected_provider)),
icon="⚠️",
)
if key is None:
return None, source
return RunConfig(provider=selected_provider, model=selected_model, api_key=user_key or None), source