summaryrefslogtreecommitdiff
path: root/htroot
diff options
context:
space:
mode:
Diffstat (limited to 'htroot')
-rw-r--r--htroot/AILab.html16
-rw-r--r--htroot/AIShield_p.html204
-rw-r--r--htroot/ConfigSearchPage_p.html2
-rw-r--r--htroot/Status.html2
-rw-r--r--htroot/env/templates/header.template30
-rw-r--r--htroot/env/templates/simpleSearchHeader.template1
-rw-r--r--htroot/env/templates/simpleheader.template1
-rw-r--r--htroot/env/templates/submenuAI.template1
-rw-r--r--htroot/yacychat.html13
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>&nbsp;</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>&nbsp;</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>&nbsp;</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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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) {