diff options
| -rw-r--r-- | htroot/yacychat.html | 92 | ||||
| -rw-r--r-- | source/net/yacy/htroot/yacychat.java | 4 |
2 files changed, 77 insertions, 19 deletions
diff --git a/htroot/yacychat.html b/htroot/yacychat.html index bc0e7f164..cfe815291 100644 --- a/htroot/yacychat.html +++ b/htroot/yacychat.html @@ -342,6 +342,16 @@ display: none; } + .search-default-options .global-option, + .search-default-options .global-label { + display: none; + } + + .search-default-options.has-global .global-option, + .search-default-options.has-global .global-label { + display: flex; + } + .composer-main { flex: 1; display: flex; @@ -726,15 +736,15 @@ <div class="chat-flow"> <div class="search-default-control"> <span>Default Dialog Augmentation:</span> - <div class="search-default-options" id="searchDefaultOptions" role="radiogroup" aria-label="Attach search results by default"> - <input type="radio" id="searchDefaultNone" name="searchDefault" value="no"/> - <label for="searchDefaultNone">no search, allow attachments</label> - <input type="radio" id="searchDefaultLocal" name="searchDefault" value="local" checked="checked"/> - <label for="searchDefaultLocal">use local search</label> - <input type="radio" id="searchDefaultGlobal" name="searchDefault" value="global"/> - <label for="searchDefaultGlobal">use global search</label> - <span class="search-default-slider" aria-hidden="true"></span> - </div> +<div class="search-default-options" id="searchDefaultOptions" role="radiogroup" aria-label="Attach search results by default"> + <input type="radio" id="searchDefaultNone" name="searchDefault" value="no"/> + <label for="searchDefaultNone">no search, allow attachments</label> + <input type="radio" id="searchDefaultLocal" name="searchDefault" value="local" checked="checked"/> + <label for="searchDefaultLocal">use local search</label> + <input type="radio" id="searchDefaultGlobal" name="searchDefault" value="global" class="global-option"/> + <label for="searchDefaultGlobal" class="global-label">use global search</label> + <span class="search-default-slider" aria-hidden="true"></span> + </div> </div> <div class="chat-messages" id="chatMessages" aria-live="polite"></div> <form id="chatForm"> @@ -788,6 +798,7 @@ <script type="text/javascript"> const SYSTEM_PROMPT = '#[system_prompt]#'; const defaultApiHost = ''; + const P2P_MODE = #[p2p_mode]# === 1; const CHAT_VFS_PATH = '/yacy/chat/chat.json'; const SETTINGS_VFS_PATH = '/yacy/chat/settings.json'; @@ -796,6 +807,7 @@ local: 'local', global: 'global' }; + const SEARCH_OPTIONS = P2P_MODE ? SEARCH_DEFAULTS : { none: 'no', local: 'local' }; const state = { messages: [], @@ -807,7 +819,7 @@ busy: false, attachment: null, searchMode: SEARCH_DEFAULTS.none, - searchDefault: SEARCH_DEFAULTS.local, + searchDefault: P2P_MODE ? SEARCH_DEFAULTS.local : SEARCH_DEFAULTS.local, assistantSeen: false, showSystem: false }; @@ -835,6 +847,15 @@ searchDefaultGlobal: document.getElementById('searchDefaultGlobal') }; + // configure search default options based on P2P mode + if (dom.searchDefaultOptions) { + if (P2P_MODE) { + dom.searchDefaultOptions.classList.add('has-global'); + } else { + dom.searchDefaultOptions.classList.remove('has-global'); + } + } + const IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg']); const TEXT_MIME_TYPES = new Set(['text/plain', 'text/markdown', 'text/x-tex', 'application/x-tex', 'application/x-latex']); const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg']); @@ -1389,13 +1410,19 @@ function setSearchModeActive(mode) { let nextMode = mode; if (mode === true) { - nextMode = state.searchDefault === SEARCH_DEFAULTS.none ? SEARCH_DEFAULTS.local : state.searchDefault; + // validate against available options + if (P2P_MODE) { + nextMode = state.searchDefault === SEARCH_DEFAULTS.none ? SEARCH_DEFAULTS.local : state.searchDefault; + } else { + nextMode = state.searchDefault === SEARCH_DEFAULTS.global ? SEARCH_DEFAULTS.local : state.searchDefault; + } } if (!nextMode || nextMode === false) { nextMode = SEARCH_DEFAULTS.none; } - if (nextMode !== SEARCH_DEFAULTS.local && nextMode !== SEARCH_DEFAULTS.global) { - nextMode = SEARCH_DEFAULTS.none; + // reject global mode when not in P2P + if (!P2P_MODE && nextMode === SEARCH_DEFAULTS.global) { + nextMode = SEARCH_DEFAULTS.local; } state.searchMode = nextMode; state.attachment = null; @@ -1415,7 +1442,9 @@ function applySearchDefaultToComposer() { if (!dom.attachmentRow || state.attachment) return; if (state.searchDefault !== SEARCH_DEFAULTS.none) { - setSearchModeActive(state.searchDefault); + // validate search default against available options + const validDefault = P2P_MODE ? state.searchDefault : state.searchDefault === SEARCH_DEFAULTS.global ? SEARCH_DEFAULTS.local : state.searchDefault; + setSearchModeActive(validDefault); } else { setSearchModeActive(SEARCH_DEFAULTS.none); } @@ -1423,11 +1452,27 @@ function updateSearchDefaultSlider() { if (!dom.searchDefaultOptions) return; + // count only visible inputs (exclude hidden global option) const inputs = Array.from(dom.searchDefaultOptions.querySelectorAll('input[name="searchDefault"]')); - const activeIndex = inputs.findIndex(input => input.checked); - const segments = inputs.length || 2; + const visibleInputs = inputs.filter(input => { + if (input === dom.searchDefaultGlobal) { + return dom.searchDefaultOptions.classList.contains('has-global'); + } + return true; + }); + const activeIndex = visibleInputs.findIndex(input => input.checked); + const segments = visibleInputs.length || 2; dom.searchDefaultOptions.style.setProperty('--segments', segments); - dom.searchDefaultOptions.style.setProperty('--active', activeIndex < 0 ? 0 : activeIndex); + // map checked input to its index among visible inputs + let displayIndex = 0; + for (const input of inputs) { + if (input === dom.searchDefaultGlobal && !dom.searchDefaultOptions.classList.contains('has-global')) { + continue; + } + if (input.checked) break; + displayIndex++; + } + dom.searchDefaultOptions.style.setProperty('--active', displayIndex); } async function getVfsClient() { @@ -1481,13 +1526,22 @@ console.warn('Failed to load search default', err); } if (stored === 'none') stored = SEARCH_DEFAULTS.none; - if (stored && Object.values(SEARCH_DEFAULTS).includes(stored)) { + // validate stored default against available options + if (!P2P_MODE && stored === SEARCH_DEFAULTS.global) { + stored = SEARCH_DEFAULTS.local; + } + if (stored && Object.values(SEARCH_OPTIONS).includes(stored)) { state.searchDefault = stored; } + // update radio buttons to reflect stored state if (dom.searchDefaultNone && state.searchDefault === SEARCH_DEFAULTS.none) { dom.searchDefaultNone.checked = true; } else if (dom.searchDefaultLocal && state.searchDefault === SEARCH_DEFAULTS.local) { dom.searchDefaultLocal.checked = true; + } else if (dom.searchDefaultGlobal && !P2P_MODE) { + // global not available, fallback to local + dom.searchDefaultLocal.checked = true; + state.searchDefault = SEARCH_DEFAULTS.local; } else if (dom.searchDefaultGlobal && state.searchDefault === SEARCH_DEFAULTS.global) { dom.searchDefaultGlobal.checked = true; } @@ -2659,7 +2713,7 @@ const target = event.target; if (!(target instanceof HTMLInputElement)) return; if (target.name !== 'searchDefault') return; - if (!Object.values(SEARCH_DEFAULTS).includes(target.value)) return; + if (!Object.values(SEARCH_OPTIONS).includes(target.value)) return; state.searchDefault = target.value; updateSearchDefaultSlider(); persistSearchDefault(); diff --git a/source/net/yacy/htroot/yacychat.java b/source/net/yacy/htroot/yacychat.java index 43b6107b5..5545d2e57 100644 --- a/source/net/yacy/htroot/yacychat.java +++ b/source/net/yacy/htroot/yacychat.java @@ -30,6 +30,10 @@ public class yacychat { final String systemPrompt = sb.getConfig("ai.system-prompt", net.yacy.http.servlets.RAGProxyServlet.LLM_SYSTEM_PROMPT_DEFAULT); prop.put("system_prompt", systemPrompt); prop.put("topmenu", sb.getConfigBool("ai.shield.show-chat-link", false) ? (sb.getConfigBool("publicTopmenu", true) ? 1 : 0) : 2); + // determine if P2P mode is active (global search available) + final boolean indexReceiveGranted = sb.getConfigBool(net.yacy.search.SwitchboardConstants.INDEX_RECEIVE_ALLOW_SEARCH, true) || (sb.isRobinsonMode() && sb.getConfig(net.yacy.search.SwitchboardConstants.CLUSTER_MODE, "").equals(net.yacy.search.SwitchboardConstants.CLUSTER_MODE_PUBLIC_CLUSTER)); + final boolean p2pmode = indexReceiveGranted; + prop.put("p2p_mode", p2pmode ? 1 : 0); // return rewrite properties return prop; |
