Spaces:
Sleeping
Sleeping
Download config/minimal_ui_patch.js from scomb2/Michel-OpenWebUI: direct link, hf CLI and curl.
- Browser
- Download file 13.4 kB
-
https://huggingface.co/spaces/scomb2/Michel-OpenWebUI/resolve/main/config/minimal_ui_patch.js
- Command line
-
hf download hf://spaces/scomb2/Michel-OpenWebUI/config/minimal_ui_patch.js
-
curl -L -o minimal_ui_patch.js https://huggingface.co/spaces/scomb2/Michel-OpenWebUI/resolve/main/config/minimal_ui_patch.js
13.4 kB
| (() => { | |
| const MONTAIGNE_SUGGESTIONS = [ | |
| { | |
| title: ['What occupies your thoughts', 'most lately?'], | |
| content: 'What occupies your thoughts most lately?' | |
| }, | |
| { | |
| title: ['Which of your habits', 'deserve examination?'], | |
| content: 'Which of my habits deserve the closest examination, and how might I begin?' | |
| }, | |
| { | |
| title: ['What do solitude and', 'conversation each reveal?'], | |
| content: "What do solitude and conversation each reveal about a person's character?" | |
| }, | |
| { | |
| title: ['How have you changed', 'without noticing?'], | |
| content: 'How can someone recognize the ways they have changed without noticing?' | |
| }, | |
| { | |
| title: ['Where does ambition', 'help or mislead you?'], | |
| content: 'Where does ambition improve a life, and where does it quietly mislead us?' | |
| }, | |
| { | |
| title: ['What truth about yourself', 'is hardest to admit?'], | |
| content: 'What kinds of truths about ourselves are the hardest to admit, and why?' | |
| } | |
| ]; | |
| const HIDE_TEXT = new Set([ | |
| 'Settings', | |
| 'Archived Chats', | |
| 'Keyboard shortcuts', | |
| 'Update your status', | |
| 'Playground', | |
| 'Admin Panel', | |
| 'Documentation', | |
| 'Releases', | |
| 'Set as default' | |
| ]); | |
| const HIDE_HREF = new Set(['/playground', '/admin']); | |
| const HIDE_ARIA = new Set(['Controls', 'Add Model', 'Remove Model', 'Voice Input', 'Voice mode']); | |
| const CHAT_COMPLETIONS_PATH = '/api/chat/completions'; | |
| const GUEST_TOKEN_KEY = 'montaigne_guest_upgrade_token'; | |
| const GUEST_CLAIM_URL_KEY = 'montaigne_guest_claim_url'; | |
| const MONTAIGNE_TOKEN_KEY = 'montaigne_access_token'; | |
| function normalize(text) { | |
| return (text || '').replace(/\s+/g, ' ').trim(); | |
| } | |
| function removeGuestBanner() { | |
| const banner = document.getElementById('montaigne-guest-banner'); | |
| if (banner) { | |
| banner.remove(); | |
| } | |
| } | |
| function closeGuestModal() { | |
| const modal = document.getElementById('montaigne-guest-modal'); | |
| if (modal) { | |
| modal.remove(); | |
| } | |
| } | |
| async function submitGuestClaim(form, statusEl) { | |
| const guestUpgradeToken = localStorage.getItem(GUEST_TOKEN_KEY); | |
| const claimUrl = localStorage.getItem(GUEST_CLAIM_URL_KEY); | |
| const username = form.querySelector('[name="username"]').value.trim(); | |
| const password = form.querySelector('[name="password"]').value; | |
| if (!guestUpgradeToken || !claimUrl) { | |
| statusEl.textContent = 'This guest session can no longer be claimed. Please refresh and try again.'; | |
| return; | |
| } | |
| if (username.length < 3) { | |
| statusEl.textContent = 'Choose a username with at least 3 characters.'; | |
| return; | |
| } | |
| if (password.length < 6) { | |
| statusEl.textContent = 'Choose a password with at least 6 characters.'; | |
| return; | |
| } | |
| statusEl.textContent = 'Creating your account...'; | |
| try { | |
| const response = await fetch(claimUrl, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| guest_upgrade_token: guestUpgradeToken, | |
| username, | |
| password | |
| }) | |
| }); | |
| const payload = await response.json(); | |
| if (!response.ok) { | |
| throw new Error(payload.detail || 'Could not create your account.'); | |
| } | |
| localStorage.setItem(MONTAIGNE_TOKEN_KEY, payload.access_token); | |
| localStorage.removeItem(GUEST_TOKEN_KEY); | |
| localStorage.removeItem(GUEST_CLAIM_URL_KEY); | |
| closeGuestModal(); | |
| removeGuestBanner(); | |
| const toast = document.createElement('div'); | |
| toast.style.cssText = | |
| 'position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:100000;' + | |
| 'background:#16311f;color:#e6f6ea;padding:10px 14px;border-radius:10px;' + | |
| 'font:13px Inter,system-ui,sans-serif;box-shadow:0 10px 30px rgba(0,0,0,.25);'; | |
| toast.textContent = 'Account created. Send your next message to continue.'; | |
| document.body.appendChild(toast); | |
| setTimeout(() => toast.remove(), 4000); | |
| } catch (error) { | |
| statusEl.textContent = error instanceof Error ? error.message : 'Could not create your account.'; | |
| } | |
| } | |
| function openGuestModal() { | |
| closeGuestModal(); | |
| const overlay = document.createElement('div'); | |
| overlay.id = 'montaigne-guest-modal'; | |
| overlay.style.cssText = | |
| 'position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;' + | |
| 'background:rgba(22,16,12,.62);padding:20px;'; | |
| const card = document.createElement('div'); | |
| card.style.cssText = | |
| 'width:min(420px,100%);border-radius:18px;padding:22px;background:#f5ede0;color:#2b2118;' + | |
| 'box-shadow:0 20px 60px rgba(0,0,0,.35);font:14px Inter,system-ui,sans-serif;'; | |
| const title = document.createElement('h2'); | |
| title.textContent = 'Create your account'; | |
| title.style.cssText = 'margin:0 0 8px;font:600 22px Georgia,serif;'; | |
| const intro = document.createElement('p'); | |
| intro.textContent = 'Keep this conversation and continue chatting with Montaigne.'; | |
| intro.style.cssText = 'margin:0 0 16px;line-height:1.45;color:#5b4a3c;'; | |
| const form = document.createElement('form'); | |
| form.style.cssText = 'display:grid;gap:12px;'; | |
| const username = document.createElement('input'); | |
| username.name = 'username'; | |
| username.placeholder = 'Username'; | |
| username.autocomplete = 'username'; | |
| username.style.cssText = | |
| 'width:100%;padding:12px 14px;border:1px solid #cfb89b;border-radius:10px;background:#fffdf9;'; | |
| const password = document.createElement('input'); | |
| password.name = 'password'; | |
| password.type = 'password'; | |
| password.placeholder = 'Password'; | |
| password.autocomplete = 'new-password'; | |
| password.style.cssText = username.style.cssText; | |
| const status = document.createElement('div'); | |
| status.style.cssText = 'min-height:18px;font-size:13px;color:#8a2f2f;'; | |
| const actions = document.createElement('div'); | |
| actions.style.cssText = 'display:flex;justify-content:flex-end;gap:10px;margin-top:4px;'; | |
| const cancel = document.createElement('button'); | |
| cancel.type = 'button'; | |
| cancel.textContent = 'Cancel'; | |
| cancel.style.cssText = | |
| 'padding:10px 14px;border:1px solid #cfb89b;border-radius:10px;background:#fff8ef;cursor:pointer;'; | |
| cancel.onclick = () => closeGuestModal(); | |
| const submit = document.createElement('button'); | |
| submit.type = 'submit'; | |
| submit.textContent = 'Create account'; | |
| submit.style.cssText = | |
| 'padding:10px 14px;border:none;border-radius:10px;background:#8b6243;color:#fff;cursor:pointer;font-weight:600;'; | |
| form.addEventListener('submit', async (event) => { | |
| event.preventDefault(); | |
| await submitGuestClaim(form, status); | |
| }); | |
| actions.appendChild(cancel); | |
| actions.appendChild(submit); | |
| form.appendChild(username); | |
| form.appendChild(password); | |
| form.appendChild(status); | |
| form.appendChild(actions); | |
| card.appendChild(title); | |
| card.appendChild(intro); | |
| card.appendChild(form); | |
| overlay.appendChild(card); | |
| overlay.addEventListener('click', (event) => { | |
| if (event.target === overlay) { | |
| closeGuestModal(); | |
| } | |
| }); | |
| document.body.appendChild(overlay); | |
| username.focus(); | |
| } | |
| function showGuestBanner() { | |
| if (document.getElementById('montaigne-guest-banner')) { | |
| return; | |
| } | |
| const banner = document.createElement('div'); | |
| banner.id = 'montaigne-guest-banner'; | |
| banner.style.cssText = | |
| 'position:fixed;bottom:0;left:0;right:0;z-index:99999;background:linear-gradient(135deg,#3d2b1f,#5c3d2e);' + | |
| 'color:#f5e6d3;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;' + | |
| 'font:14px Inter,system-ui,sans-serif;box-shadow:0 -2px 12px rgba(0,0,0,.3);'; | |
| const message = document.createElement('span'); | |
| message.textContent = 'You have used your 5 free messages. Create a free account to continue chatting with Montaigne.'; | |
| const button = document.createElement('button'); | |
| button.type = 'button'; | |
| button.textContent = 'Create free account'; | |
| button.style.cssText = | |
| 'background:#c9a96e;color:#2b1d0e;padding:8px 18px;border:none;border-radius:6px;' + | |
| 'font-weight:600;white-space:nowrap;cursor:pointer;'; | |
| button.onclick = () => openGuestModal(); | |
| const close = document.createElement('button'); | |
| close.type = 'button'; | |
| close.textContent = 'x'; | |
| close.style.cssText = | |
| 'background:none;border:none;color:#f5e6d3;font-size:20px;cursor:pointer;padding:0 4px;line-height:1;'; | |
| close.onclick = () => removeGuestBanner(); | |
| banner.appendChild(message); | |
| banner.appendChild(button); | |
| banner.appendChild(close); | |
| document.body.appendChild(banner); | |
| } | |
| function installFetchPatch() { | |
| if (window.__montaigneFetchPatched) { | |
| return; | |
| } | |
| window.__montaigneFetchPatched = true; | |
| const originalFetch = window.fetch.bind(window); | |
| window.fetch = async (...args) => { | |
| try { | |
| const input = args[0]; | |
| const rawUrl = input instanceof Request ? input.url : String(input); | |
| const url = new URL(rawUrl, window.location.origin); | |
| if (url.pathname === CHAT_COMPLETIONS_PATH) { | |
| const body = args[1] && args[1].body; | |
| if (typeof body === 'string') { | |
| try { | |
| const parsed = JSON.parse(body); | |
| parsed.variables = parsed.variables || {}; | |
| const montaigneToken = localStorage.getItem(MONTAIGNE_TOKEN_KEY); | |
| if (montaigneToken) { | |
| parsed.variables.montaigne_token = montaigneToken; | |
| } | |
| args[1] = { ...args[1], body: JSON.stringify(parsed) }; | |
| } catch (_) { | |
| // Ignore non-JSON payloads. | |
| } | |
| } | |
| } | |
| } catch (_) { | |
| // Ignore URL parsing errors. | |
| } | |
| const response = await originalFetch(...args); | |
| try { | |
| const input = args[0]; | |
| const rawUrl = input instanceof Request ? input.url : String(input); | |
| const url = new URL(rawUrl, window.location.origin); | |
| if (url.pathname === '/api/config') { | |
| const payload = await response.clone().json(); | |
| payload.default_prompt_suggestions = MONTAIGNE_SUGGESTIONS; | |
| const headers = new Headers(response.headers); | |
| headers.set('content-type', 'application/json'); | |
| headers.delete('content-length'); | |
| return new Response(JSON.stringify(payload), { | |
| status: response.status, | |
| statusText: response.statusText, | |
| headers | |
| }); | |
| } | |
| if (url.pathname === CHAT_COMPLETIONS_PATH && response.status === 403) { | |
| const payload = await response.clone().json().catch(() => null); | |
| if (payload && payload.code === 'guest_limit_reached' && payload.guest_upgrade_token && payload.claim_guest_url) { | |
| localStorage.setItem(GUEST_TOKEN_KEY, payload.guest_upgrade_token); | |
| localStorage.setItem(GUEST_CLAIM_URL_KEY, payload.claim_guest_url); | |
| showGuestBanner(); | |
| } | |
| } | |
| } catch (_) { | |
| // Keep the UI resilient. | |
| } | |
| return response; | |
| }; | |
| } | |
| function hide(el) { | |
| if (!el || el.dataset.montaigneHidden === '1') { | |
| return; | |
| } | |
| el.dataset.montaigneHidden = '1'; | |
| el.style.display = 'none'; | |
| } | |
| function hideMenuItem(el) { | |
| hide(el.closest('button, a, [role="menuitem"]') || el); | |
| } | |
| function hideModelSelector(trigger) { | |
| hide(trigger); | |
| let node = trigger; | |
| for (let i = 0; i < 6 && node; i += 1) { | |
| const className = typeof node.className === 'string' ? node.className : ''; | |
| if (className.includes('overflow-hidden')) { | |
| hide(node.parentElement || node); | |
| return; | |
| } | |
| node = node.parentElement; | |
| } | |
| hide(trigger); | |
| } | |
| function applyMinimalUi() { | |
| document | |
| .querySelectorAll('[id^="model-selector-"][id$="-button"]') | |
| .forEach(hideModelSelector); | |
| document.querySelectorAll('#voice-input-button, [aria-label="Voice mode"]').forEach(hide); | |
| document.querySelectorAll('[aria-label^="Get information on "]').forEach(hide); | |
| document.querySelectorAll('[role="dialog"], dialog').forEach((el) => { | |
| const text = normalize(el.textContent); | |
| if (text.includes("What's New") || text.includes('Release Notes')) { | |
| const closeButton = el.querySelector('button[aria-label="Close"]'); | |
| if (closeButton) { | |
| closeButton.click(); | |
| } | |
| hide(el); | |
| } | |
| }); | |
| document.querySelectorAll('button, a, [role="menuitem"]').forEach((el) => { | |
| const text = normalize(el.textContent); | |
| const aria = normalize(el.getAttribute('aria-label')); | |
| const href = el.getAttribute('href'); | |
| if (HIDE_TEXT.has(text) || HIDE_ARIA.has(aria) || HIDE_HREF.has(href)) { | |
| hideMenuItem(el); | |
| } | |
| }); | |
| document.querySelectorAll('#temporary-chat-button').forEach(hide); | |
| } | |
| installFetchPatch(); | |
| const run = () => window.requestAnimationFrame(applyMinimalUi); | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', run, { once: true }); | |
| } else { | |
| run(); | |
| } | |
| new MutationObserver(run).observe(document.documentElement, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| })(); | |