diff --git a/app/pages/2_Settings.py b/app/pages/2_Settings.py index b16819d..f5e54c6 100644 --- a/app/pages/2_Settings.py +++ b/app/pages/2_Settings.py @@ -9,6 +9,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent)) import streamlit as st import yaml +import os as _os from scripts.user_profile import UserProfile @@ -79,13 +80,21 @@ Return ONLY valid JSON in this exact format: _show_finetune = bool(_profile and _profile.inference_profile in ("single-gpu", "dual-gpu")) -tab_profile, tab_search, tab_llm, tab_notion, tab_services, tab_resume, tab_email, tab_skills, tab_finetune = st.tabs( - ["👤 My Profile", "🔎 Search", "🤖 LLM Backends", "📚 Notion", - "🔌 Services", "📝 Resume Profile", "📧 Email", "🏷️ Skills", "🎯 Fine-Tune"] -) - USER_CFG = CONFIG_DIR / "user.yaml" +_dev_mode = _os.getenv("DEV_MODE", "").lower() in ("true", "1", "yes") +_u_for_dev = yaml.safe_load(USER_CFG.read_text()) or {} if USER_CFG.exists() else {} +_show_dev_tab = _dev_mode or bool(_u_for_dev.get("dev_tier_override")) + +_tab_names = [ + "👤 My Profile", "🔎 Search", "🤖 LLM Backends", "📚 Notion", + "🔌 Services", "📝 Resume Profile", "📧 Email", "🏷️ Skills", "🎯 Fine-Tune" +] +if _show_dev_tab: + _tab_names.append("🛠️ Developer") +_all_tabs = st.tabs(_tab_names) +tab_profile, tab_search, tab_llm, tab_notion, tab_services, tab_resume, tab_email, tab_skills, tab_finetune = _all_tabs[:9] + with tab_profile: from scripts.user_profile import UserProfile as _UP, _DEFAULTS as _UP_DEFAULTS import yaml as _yaml_up @@ -1020,3 +1029,34 @@ with tab_finetune: if st.button("← Back", key="ft_back3"): st.session_state.ft_step = 2 st.rerun() + +# ── Developer tab ───────────────────────────────────────────────────────────── +if _show_dev_tab: + with _all_tabs[-1]: + st.subheader("Developer Settings") + st.caption("These settings are for local testing only and are never used in production.") + + st.markdown("**Tier Override**") + st.caption("Instantly switches effective tier without changing your billing tier.") + from app.wizard.tiers import TIERS as _TIERS + _current_override = _u_for_dev.get("dev_tier_override") or "" + _override_opts = ["(none — use real tier)"] + _TIERS + _override_idx = (_TIERS.index(_current_override) + 1) if _current_override in _TIERS else 0 + _new_override = st.selectbox("dev_tier_override", _override_opts, index=_override_idx) + _new_override_val = None if _new_override.startswith("(none") else _new_override + + if st.button("Apply tier override", key="apply_tier_override"): + _u_for_dev["dev_tier_override"] = _new_override_val + save_yaml(USER_CFG, _u_for_dev) + st.success(f"Tier override set to: {_new_override_val or 'none'}. Page will reload.") + st.rerun() + + st.divider() + st.markdown("**Wizard Reset**") + st.caption("Sets `wizard_complete: false` to re-enter the wizard without deleting your config.") + + if st.button("↩ Reset wizard", key="reset_wizard"): + _u_for_dev["wizard_complete"] = False + _u_for_dev["wizard_step"] = 0 + save_yaml(USER_CFG, _u_for_dev) + st.success("Wizard reset. Reload the app to re-run setup.") diff --git a/tests/test_dev_tab.py b/tests/test_dev_tab.py new file mode 100644 index 0000000..13a59af --- /dev/null +++ b/tests/test_dev_tab.py @@ -0,0 +1,32 @@ +import sys +from pathlib import Path +import yaml +sys.path.insert(0, str(Path(__file__).parent.parent)) + + +def test_dev_tab_visible_when_override_set(tmp_path): + p = tmp_path / "user.yaml" + p.write_text("name: T\nemail: t@t.com\ncareer_summary: x\ndev_tier_override: premium\n") + from scripts.user_profile import UserProfile + u = UserProfile(p) + assert u.dev_tier_override == "premium" + assert u.effective_tier == "premium" + + +def test_dev_tab_not_visible_without_override(tmp_path): + p = tmp_path / "user.yaml" + p.write_text("name: T\nemail: t@t.com\ncareer_summary: x\ntier: free\n") + from scripts.user_profile import UserProfile + u = UserProfile(p) + assert u.dev_tier_override is None + assert u.effective_tier == "free" + + +def test_can_use_uses_effective_tier(tmp_path): + p = tmp_path / "user.yaml" + p.write_text("name: T\nemail: t@t.com\ncareer_summary: x\ntier: free\ndev_tier_override: premium\n") + from scripts.user_profile import UserProfile + from app.wizard.tiers import can_use + u = UserProfile(p) + assert can_use(u.effective_tier, "model_fine_tuning") is True + assert can_use(u.tier, "model_fine_tuning") is False