Skip to content
This repository was archived by the owner on Aug 21, 2026. It is now read-only.
2 changes: 1 addition & 1 deletion .github/workflows/ai-maintenance-manual.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: AI Site Maintenance (manual)
name: AI Site Maintenance (manual)
on:
workflow_dispatch:

Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/ai-maintenance-run.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
on:
push:
branches: [ main ]
on:
workflow_dispatch:

permissions:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ai-maintenance-v3.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: AI Site Maintenance (v3, manual)
name: AI Site Maintenance (v3, manual)
on:
workflow_dispatch:

Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/ai-maintenance.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: AI Site Maintenance
name: AI Site Maintenance
on:
schedule:
- cron: "17 2 * * *"
workflow_dispatch: {}
workflow_dispatch:

permissions:
contents: write
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/ai-ops.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: AI Ops Issue to PR
name: AI Ops Issue to PR
on:
issues:
types: [opened, edited, labeled]
workflow_dispatch:

permissions:
contents: write
Expand Down
3 changes: 3 additions & 0 deletions _layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
Last updated: {{ page.last_updated }}
</p>
{% endif %}
<script src="{{ '/assets/gpt5.js' | relative_url }}?v=2" defer></script>
<script src="{{ '/assets/gpt5-actions.js' | relative_url }}?v=1" defer></script>


</main>
{% include footer.html %}
Expand Down
81 changes: 81 additions & 0 deletions assets/gpt5-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// ES5-safe helpers that use window.gpt5 (from /assets/gpt5.js)
(function () {
if (!window.gpt5) {
console.error("gpt5 helper not found. Include /assets/gpt5.js first.");
return;
}

function $(id) { return document.getElementById(id); }

function textFromPage() {
var el =
document.querySelector("main") ||
document.querySelector("article") ||
document.querySelector(".content") ||
document.querySelector(".post-content") ||
document.getElementById("content") ||
document.body;
var t = el && (el.innerText || el.textContent) || "";
t = (t || "").replace(/\s+/g, " ").trim();
if (t.length > 6000) t = t.slice(0, 6000); // keep the demo snappy
return t;
}

function setBtn(disabled, label) {
var b = $("ai-summary-btn");
if (b) {
b.disabled = !!disabled;
if (label != null) b.textContent = label;
}
}
document.addEventListener("DOMContentLoaded", function () {
var btn = document.getElementById("ai-summary-btn");
var stop = document.getElementById("ai-summary-stop");
var out = document.getElementById("ai-summary");
if (!btn || !out || !stop) return;

function setBtn(disabled, label) {
btn.disabled = !!disabled;
if (label != null) btn.textContent = label;
}

stop.addEventListener("click", function () {
try { gpt5.abort(); } catch (e) {}
setBtn(false, "AI Summary");
});

btn.addEventListener("click", function () {
var el =
document.querySelector("main") ||
document.querySelector("article") ||
document.querySelector(".content") ||
document.querySelector(".post-content") ||
document.getElementById("content") ||
document.body;
var content = el && (el.innerText || el.textContent) || "";
content = (content || "").replace(/\s+/g, " ").trim();
if (content.length > 6000) content = content.slice(0, 6000);

if (!content) {
out.textContent = "Sorry—no readable content found on this page.";
return;
}

out.textContent = "Thinking…";
setBtn(true, "Summarizing…");
var full = "";

gpt5.stream({
system: "You are LLbot for OraDigit.com. Summarize for executives and prospects. 5–7 bullet points. Clear, concrete, jargon-light.",
messages: [{ role: "user", content: "Summarize this page for a prospective client:\n\n" + content }],
onToken: function (t) { full += t; out.textContent = full; }
})
.then(function () { setBtn(false, "AI Summary"); })
.catch(function (e) {
out.textContent = "Error: " + (e && e.message ? e.message : e);
setBtn(false, "AI Summary");
});
});
});


102 changes: 102 additions & 0 deletions assets/gpt5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Minimal client for OraDigit's GPT proxy (SSE). ES5-compatible.
// Adds smart token spacing and an abort() helper.
(function () {
var API = "https://auth.oradigit.com/api/chat"; // mapped to chat5
var _controller = null;

function needsSpace(prev, next) {
if (!prev || !next) return false;
var a = prev.slice(-1);
var b = next.charAt(0);
// insert a space when two alphanumerics touch (e.g., "Hello" + "How")
return /[A-Za-z0-9]/.test(a) && /[A-Za-z0-9]/.test(b);
}

function stream(opts) {
if (!opts) opts = {};
if (!Array.isArray(opts.messages)) throw new Error("messages[] required");

var payload = { messages: opts.messages };
if (opts.system) payload.system = opts.system;
if (opts.model) payload.model = opts.model;

_controller = new AbortController();
var useSignal = opts.signal || _controller.signal;

return fetch(API, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: useSignal
}).then(function (resp) {
var ct = resp.headers.get("content-type");
if (!resp.ok) {
return resp.text().then(function (txt) {
try { var j = JSON.parse(txt); throw new Error(j.error || j.message || ("HTTP " + resp.status)); }
catch (e) { throw new Error(txt || ("HTTP " + resp.status)); }
});
}

if (ct && ct.indexOf("text/event-stream") !== -1) {
var reader = resp.body.getReader();
var decoder = new TextDecoder();
var buffer = "";
var full = "";

function pump() {
return reader.read().then(function (r) {
if (r.done) return full;

buffer += decoder.decode(r.value, { stream: true });
var parts = buffer.split("\n\n");
buffer = parts.pop() || "";

for (var i = 0; i < parts.length; i++) {
var evt = parts[i];
if (!evt.trim()) continue;
var lines = evt.split("\n");
var type = (lines[0] || "").replace(/^event:\s*/, "").trim();
var data = (lines.slice(1).join("\n") || "").replace(/^data:\s*/, "");

if (type === "message") {
var chunk = data;
if (needsSpace(full, chunk)) chunk = " " + chunk;
full += chunk;
if (typeof opts.onToken === "function") opts.onToken(chunk);
} else if (type === "error") {
try { var j = JSON.parse(data); throw new Error(j.message || "Server error"); }
catch (e) { throw new Error("Server error"); }
}
// ignore: open/info/done
}
return pump();
});
}
return pump();
}

// Non-SSE fallback
return resp.json().then(function (json) {
if (json && json.error) throw new Error(json.error);
return json;
})["catch"](function () { return {}; });
});
}

function ask(prompt, opts) {
opts = opts || {};
return stream({
system: opts.system || "You are LLbot for OraDigit.com. Be concise.",
model: opts.model,
messages: [{ role: "user", content: prompt }],
onToken: opts.onToken,
signal: opts.signal
});
}

function abort() {
if (_controller) try { _controller.abort(); } catch (e) {}
}

window.gpt5 = { stream: stream, ask: ask, abort: abort };
})();
7 changes: 7 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ <h3>Manage Your Cookie Preferences</h3>
}
});
</script>
<div class="ai-summary-card">
<div style="display:flex; gap:.5rem; align-items:center;">
<button id="ai-summary-btn" type="button">AI Summary</button>
<button id="ai-summary-stop" type="button">Stop</button>
</div>
<div id="ai-summary" aria-live="polite"></div>
</div>


<!-- Cookie Script -->
Expand Down