diff options
| author | Michael Peter Christen <mc@yacy.net> | 2025-12-08 00:13:38 +0100 |
|---|---|---|
| committer | Michael Peter Christen <mc@yacy.net> | 2025-12-08 00:13:38 +0100 |
| commit | c5801d3215a0969bcf90fb2d882775302cd92f19 (patch) | |
| tree | 232011e6090ee0100ab08e5c13c3991d1a413efa /htroot | |
| parent | eed704d23bc53e5d0359072e5e2134b469ae2eef (diff) | |
added AIShield config page for chat access settings. Also added chat to top menu in case that was wanted by the user. Also added the AILab to the main menu.
Diffstat (limited to 'htroot')
| -rw-r--r-- | htroot/AILab.html | 16 | ||||
| -rw-r--r-- | htroot/AIShield_p.html | 204 | ||||
| -rw-r--r-- | htroot/ConfigSearchPage_p.html | 2 | ||||
| -rw-r--r-- | htroot/Status.html | 2 | ||||
| -rw-r--r-- | htroot/env/templates/header.template | 30 | ||||
| -rw-r--r-- | htroot/env/templates/simpleSearchHeader.template | 1 | ||||
| -rw-r--r-- | htroot/env/templates/simpleheader.template | 1 | ||||
| -rw-r--r-- | htroot/env/templates/submenuAI.template | 1 | ||||
| -rw-r--r-- | htroot/yacychat.html | 13 |
9 files changed, 250 insertions, 20 deletions
diff --git a/htroot/AILab.html b/htroot/AILab.html index cbf330393..caa89d83b 100644 --- a/htroot/AILab.html +++ b/htroot/AILab.html @@ -313,18 +313,18 @@ <span class="status-pill">Needs setup</span> </div> <h3>Define a shield</h3> - <p>Add guardrails: moderation prompts, content filters, or safety rules that wrap every request.</p> + <p>Add guardrails: access rates, grant or deny non-localhost access. Activate the front page link for chat to complete this quest.</p> <div class="quest-body"> - <div class="quest-visual"> - <img src="env/grafics/AILab_shield.png" alt="Shield definition" width="128" height="128" /> - </div> - <div class="quest-actions"> - <a class="btn btn-info btn-sm" href="ConfigProperties_p.html">Open shield settings</a><br /> - <span class="quest-note">Store your shield directives (system prompts, stop words) as properties, then exercise them in chat.</span> - </div> + <div class="quest-visual"> + <img src="env/grafics/AILab_shield.png" alt="Shield definition" width="128" height="128" /> + </div> + <div class="quest-actions"> + <a class="btn btn-info btn-sm" href="AIShield_p.html">Open shield settings</a><br /> + <span class="quest-note">Store your shield directives (system prompts, stop words) as properties, then exercise them in chat.</span> </div> </div> </div> + </div> </div> <script type="text/javascript"> diff --git a/htroot/AIShield_p.html b/htroot/AIShield_p.html new file mode 100644 index 000000000..dcc7d8ecb --- /dev/null +++ b/htroot/AIShield_p.html @@ -0,0 +1,204 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>YaCy '#[clientname]#': AI Shield</title> + #%env/templates/metas.template%# + <style type="text/css"> + .shield-card { + border: 1px solid #e6e9ef; + border-left: 6px solid #5bc0de; + padding: 16px; + margin-bottom: 14px; + background: #fff; + box-shadow: 0 3px 10px rgba(0,0,0,0.06); + } + .shield-card h3 { + margin-top: 0; + margin-bottom: 6px; + color: #0f2b46; + } + .shield-card p { + margin: 0 0 8px 0; + color: #3b4a5e; + } + .shield-inline { + display: flex; + gap: 16px; + flex-wrap: wrap; + align-items: center; + } + .shield-inline label { + margin: 0; + } + .shield-rate { + max-width: 120px; + } + + .telemetry-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 12px; + margin-top: 10px; + } + + .telemetry-item { + border: 1px solid #e6e9ef; + border-radius: 6px; + padding: 10px; + background: #f9fbff; + box-shadow: 0 2px 6px rgba(0,0,0,0.04); + } + + .telemetry-label { + font-weight: 700; + color: #0f2b46; + margin-bottom: 4px; + } + + .gauge { + position: relative; + height: 12px; + background: #e9edf5; + border-radius: 999px; + overflow: hidden; + } + + .gauge-fill { + height: 100%; + width: 0%; + border-radius: 999px; + transition: width 0.3s ease; + } + + .gauge-meta { + margin-top: 4px; + font-size: 0.9em; + color: #3b4a5e; + display: flex; + justify-content: space-between; + } + + .gauge-green { background: #5cb85c; } + .gauge-amber { background: #f0ad4e; } + .gauge-red { background: #d9534f; } + .gauge-neutral { background: #5bc0de; } + </style> + </head> + <body id="IndexControl"> + #%env/templates/header.template%# + #%env/templates/submenuAI.template%# + + <h2>Wire RAG Retrieval Shield</h2> + <p>Control who can access the chat interface and rate-limit non-localhost clients to protect your peer and LLM backends from overload.</p> + + <form method="post" action="AIShield_p.html" id="shieldForm"> + <input type="hidden" name="submit" value="1" /> + <div class="shield-card"> + <h3>Overall Load Protection</h3> + <p>Recent access volume across all clients (localhost included). You can enforce global limits here to protect the host.</p> + <div class="telemetry-grid"> + <div class="telemetry-item"> + <div class="telemetry-label">Requests / minute</div> + <div class="gauge"><div class="gauge-fill" id="gaugeMinute"></div></div> + <div class="gauge-meta"> + <span id="gaugeMinuteValue">#[telemetry.per-minute]#</span> + <span id="gaugeMinuteLimit">#[ai.shield.all.per-minute]#</span> + </div> + </div> + <div class="telemetry-item"> + <div class="telemetry-label">Requests / hour</div> + <div class="gauge"><div class="gauge-fill" id="gaugeHour"></div></div> + <div class="gauge-meta"> + <span id="gaugeHourValue">#[telemetry.per-hour]#</span> + <span id="gaugeHourLimit">#[ai.shield.all.per-hour]#</span> + </div> + </div> + <div class="telemetry-item"> + <div class="telemetry-label">Requests / day</div> + <div class="gauge"><div class="gauge-fill" id="gaugeDay"></div></div> + <div class="gauge-meta"> + <span id="gaugeDayValue">#[telemetry.per-day]#</span> + <span id="gaugeDayLimit">#[ai.shield.all.per-day]#</span> + </div> + </div> + </div> + <p style="margin-top:8px;"> + <label> + <input type="checkbox" name="ai.shield.limit-all" id="limitAll" #(ai.shield.limit-all)#::checked="checked"#(/ai.shield.limit-all)# /> + Limit for all requests, including localhost + </label> + </p> + <div class="shield-inline"> + <label>Per minute: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.all.per-minute" id="allMinute" value="#[ai.shield.all.per-minute]#" /></label> + <label>Per hour: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.all.per-hour" id="allHour" value="#[ai.shield.all.per-hour]#" /></label> + <label>Per day: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.all.per-day" id="allDay" value="#[ai.shield.all.per-day]#" /></label> + </div> + </div> + + <div class="shield-card"> + <h3>Guest Access Control & Rate Limits</h3> + <p>By default only localhost may reach the chat UI. Enable non-localhost access and throttle requests to reduce abuse.</p> + <label> + <input type="checkbox" name="ai.shield.allow-nonlocalhost" id="allowNonLocal" #(ai.shield.allow-nonlocalhost)#::checked="checked"#(/ai.shield.allow-nonlocalhost)# /> + Allow non-localhost clients to access the chat interface + </label> + <p style="margin-top:8px;">Requests from non-localhost will be throttled using these caps:</p> + <div class="shield-inline"> + <label>Per minute: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.rate.per-minute" id="rateMinute" value="#[ai.shield.rate.per-minute]#" /></label> + <label>Per hour: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.rate.per-hour" id="rateHour" value="#[ai.shield.rate.per-hour]#" /></label> + <label>Per day: <input type="number" class="form-control shield-rate" min="0" name="ai.shield.rate.per-day" id="rateDay" value="#[ai.shield.rate.per-day]#" /></label> + </div> + </div> + + <div class="shield-card"> + <h3>Front Page Link</h3> + <p>Expose a shortcut to the chat UI on the search front page if you want users to discover it.</p> + <label> + <input type="checkbox" name="ai.shield.show-chat-link" id="showLink" #(ai.shield.show-chat-link)#::checked="checked"#(/ai.shield.show-chat-link)# /> + Show a link to yacychat.html on the search front page + </label> + </div> + + <button type="submit" class="btn btn-primary">Save Shield Settings</button> + </form> + + <script type="text/javascript"> + (function() { + const allowBox = document.getElementById("allowNonLocal"); + const rateInputs = [document.getElementById("rateMinute"), document.getElementById("rateHour"), document.getElementById("rateDay")]; + const limitAllBox = document.getElementById("limitAll"); + const allRates = [document.getElementById("allMinute"), document.getElementById("allHour"), document.getElementById("allDay")]; + function syncRates() { + const enabled = allowBox && allowBox.checked; + rateInputs.forEach(inp => { if (inp) inp.disabled = !enabled; }); + const allEnabled = limitAllBox && limitAllBox.checked; + allRates.forEach(inp => { if (inp) inp.disabled = !allEnabled; }); + } + if (allowBox) { + allowBox.addEventListener("change", syncRates); + } + if (limitAllBox) { + limitAllBox.addEventListener("change", syncRates); + } + syncRates(); + + function updateGauge(id, valueId, limitId) { + const fill = document.getElementById(id); + const valEl = document.getElementById(valueId); + const limitEl = document.getElementById(limitId); + if (!fill || !valEl || !limitEl) return; + const current = parseInt(valEl.textContent, 10) || 0; + const limit = parseInt(limitEl.textContent.replace('/', '').trim(), 10) || 0; + let pct = limit > 0 ? Math.min(100, Math.round((current / limit) * 100)) : 0; + fill.style.width = (limit > 0 ? pct : 100) + "%"; + fill.className = "gauge-fill " + (limit > 0 ? (pct < 60 ? "gauge-green" : pct < 90 ? "gauge-amber" : "gauge-red") : "gauge-neutral"); + } + updateGauge("gaugeMinute", "gaugeMinuteValue", "gaugeMinuteLimit"); + updateGauge("gaugeHour", "gaugeHourValue", "gaugeHourLimit"); + updateGauge("gaugeDay", "gaugeDayValue", "gaugeDayLimit"); + })(); + </script> + + #%env/templates/footer.template%# + </body> +</html> diff --git a/htroot/ConfigSearchPage_p.html b/htroot/ConfigSearchPage_p.html index 381006e24..a8e69849c 100644 --- a/htroot/ConfigSearchPage_p.html +++ b/htroot/ConfigSearchPage_p.html @@ -186,7 +186,7 @@ <div style="float: left;"> <fieldset class="yacys"> <div class="input-group"> - <input type="text" class="form-control searchinput typeahead" size="40" maxlength="80" placeholder="Web Search by the People, for the People" name="query" /> + <input type="text" class="form-control searchinput typeahead" size="40" maxlength="80" placeholder="search..." name="query" /> <div class="input-group-btn"> <button id="Enter" class="btn btn-default" type="submit">search</button> </div> diff --git a/htroot/Status.html b/htroot/Status.html index e2933c49f..3a7d16e4f 100644 --- a/htroot/Status.html +++ b/htroot/Status.html @@ -224,6 +224,8 @@ <!--[if IE]> </div> <![endif]--> + + <iframe src="/env/donate.html" style="border:none;"></iframe> #%env/templates/footer.template%# </body> diff --git a/htroot/env/templates/header.template b/htroot/env/templates/header.template index b42d9a2c2..360e94e52 100644 --- a/htroot/env/templates/header.template +++ b/htroot/env/templates/header.template @@ -106,7 +106,7 @@ <li> </li> <li id="header_community"> <form action="https://community.searchlab.eu" target="_blank" method="get"> - <button accesskey="f" type="submit" class="btn btn-inverse navbar-btn label-info" title="Community"> + <button accesskey="f" type="submit" class="btn btn-inverse navbar-btn label-primary" title="Community"> <span class="glyphicon glyphicon-user"></span> <span class="hidden-sm"> Forum</span> </button> @@ -149,13 +149,24 @@ <li><a href="#">Please help! We need financial help to move on with the development!</a></li> </ul> </li> + #(navigation-showChatLink)#:: <li> </li> - <li id="header_administration"> + <li id="header_chat"> + <form action="yacychat.html" method="get"> + <button accesskey="c" type="submit" class="btn btn-inverse navbar-btn label-info" title="Chat"> + <span class="glyphicon glyphicon-console"></span> + <span class="hidden-sm"> Chat</span> + </button> + </form> + </li> + #(/navigation-showChatLink)# + <li> </li> + <li id="header_search"> <form action="index.html" method="get"> #(authorized)#:: <input type="hidden" name="auth" value=""/> #(/authorized)# - <button accesskey="s" type="submit" class="btn btn-inverse navbar-btn label-primary" title="Search"> + <button accesskey="s" type="submit" class="btn btn-inverse navbar-btn label-info" title="Search"> <span class="glyphicon glyphicon-search"></span> <span class="hidden-sm"> Search</span> </button> @@ -178,8 +189,7 @@ > <li><h3>First Steps</h3></li> <li><a href="ConfigBasic.html" class="MenuItemLink">Use Case & Account</a></li> - <li><a href="CrawlStartSite.html" class="MenuItemLink">Load Web Pages, Crawler</a></li> - <li><a href="Performance_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">RAM/Disk Usage & Updates</a></li> + <li><a href="CrawlStartSite.html" class="MenuItemLink">Grab a whole site</a></li> </ul> #(navigation-advanced)#<script>$("#first-steps").popover();</script>::#(/navigation-advanced)# @@ -201,17 +211,19 @@ #(navigation-advanced)#:: <ul class="nav nav-sidebar menugroup"> <li><h3>Production</h3></li> - <li><a href="CrawlStartExpert.html" class="MenuItemLink">Advanced Crawler</a></li> - <li><a href="IndexPackGenerator_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Index Export/Import</a></li> + <li><a href="CrawlStartExpert.html" class="MenuItemLink">Crawler</a></li> + <li><a href="AILab.html" class="MenuItemLink">AI Lab</a></li> + <li><a href="IndexPackGenerator_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">YaCy Packs & Import/Export</a></li> + <li><a href="Table_API_p.html?sort=-date_recording" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Process Scheduler</a></li> <li><a href="Vocabulary_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Content Semantic</a></li> - <li><a href="CrawlCheck_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Target Analysis</a></li> + <li><a href="CrawlCheck_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Target Analysis</a></li> </ul> <ul class="nav nav-sidebar menugroup"> <li><h3>Administration</h3></li> <li><a href="IndexControlURLs_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Index Administration</a></li> <li><a href="Settings_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">System Administration</a></li> <li><a href="Blacklist_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Filter & Blacklists</a></li> - <li><a href="Table_API_p.html?sort=-date_recording" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">Process Scheduler</a></li> + <li><a href="Performance_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">RAM/Disk Usage & Updates</a></li> </ul> <ul class="nav nav-sidebar menugroup"> <li><h3>Search Portal Integration</h3></li> diff --git a/htroot/env/templates/simpleSearchHeader.template b/htroot/env/templates/simpleSearchHeader.template index 35fdf067c..5637778ca 100644 --- a/htroot/env/templates/simpleSearchHeader.template +++ b/htroot/env/templates/simpleSearchHeader.template @@ -40,6 +40,7 @@ <li id="header_websearch"><a href="index.html#(authSearch)#::?auth#(/authSearch)#" onclick="this.href='index.html?#(authSearch)#::auth&#(/authSearch)#former='+encodeURIComponent(document.searchform.search.value)">Web Search</a></li> <li id="header_filesearch"><a href="yacyinteractive.html" onclick="this.href='yacyinteractive.html?handover='+document.searchform.search.value">File Search</a></li> <li id="header_comparesearch"><a href="compare_yacy.html?display=0">Compare Search</a></li> + #(navigation-showChatLink)#::<li id="header_chat"><a href="yacychat.html">Chat</a></li>#(/navigation-showChatLink)# <li id="header_urlviewer"><a href="ViewFile.html">URL Viewer</a></li> <!--<li><a href="yacysearch_location.html">Location Search</a></li>--> <li class="divider" role="separator"></li> diff --git a/htroot/env/templates/simpleheader.template b/htroot/env/templates/simpleheader.template index 3112f4601..f58a66265 100644 --- a/htroot/env/templates/simpleheader.template +++ b/htroot/env/templates/simpleheader.template @@ -20,6 +20,7 @@ <li id="header_websearch"><a href="index.html#(authorized)#::?auth#(/authorized)#" onclick="this.href='index.html?#(authorized)#::auth&#(/authorized)#former='+encodeURIComponent(document.searchform.search.value)">Web Search</a></li> <li id="header_filesearch"><a href="yacyinteractive.html" onclick="this.href='yacyinteractive.html?handover='+document.searchform.search.value">File Search</a></li> <li id="header_comparesearch"><a href="compare_yacy.html?display=0">Compare Search</a></li> + #(navigation-showChatLink)#::<li id="header_chat"><a href="yacychat.html">Chat</a></li>#(/navigation-showChatLink)# <li id="header_urlviewer"><a href="ViewFile.html">URL Viewer</a></li> <!--<li><a href="yacysearch_location.html">Location Search</a></li>--> <li class="divider" role="separator"></li> diff --git a/htroot/env/templates/submenuAI.template b/htroot/env/templates/submenuAI.template index 614dff4a1..10a72c935 100644 --- a/htroot/env/templates/submenuAI.template +++ b/htroot/env/templates/submenuAI.template @@ -4,6 +4,7 @@ <li><a href="AILab.html" class="MenuItemLink">AI Lab</a></li> <li><a href="LLMSelection_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">LLM Selection</a></li> <li><a href="RAGConfig_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">RAG Config</a></li> + <li><a href="AIShield_p.html" class="MenuItemLink #(authorized)#lock::unlock#(/authorized)#">AI Shield</a></li> <li><a href="yacychat.html" class="MenuItemLink">Chat</a></li> </ul> </div> diff --git a/htroot/yacychat.html b/htroot/yacychat.html index 26ee71cd1..ff68f18cf 100644 --- a/htroot/yacychat.html +++ b/htroot/yacychat.html @@ -542,8 +542,14 @@ </style> </head> <body id="IndexControl"> - #%env/templates/header.template%# - #%env/templates/submenuAI.template%# + #(topmenu)# + #%env/templates/embeddedheader.template%# + :: + #%env/templates/simpleheader.template%# + :: + #%env/templates/header.template%# + #%env/templates/submenuAI.template%# + #(/topmenu)# <h2>YaCy Chat</h2> <p>Chat with your configured LLM using the local YaCy settings. Requests are sent to the same host that served this page.</p> @@ -1103,6 +1109,9 @@ body: JSON.stringify(payload) }); if (!response.ok) { + if (response.status === 429) { + throw new Error('Rate limit reached: please wait and try again. The server is protecting itself from overload.'); + } throw new Error(`Request failed: ${response.status} ${response.statusText}`); } if (!response.body) { |
