Fusion AI, powered by HAL 8
The hub's assistant becomes a consumer HAL 8 chat: - The button is HAL 8's red eye (the real logo); the header reads POWERED BY HAL 8. - One control, a Standard | Incognito pill. Standard keeps the conversation in this browser; Incognito keeps nothing and asks the server for no retention. - Always on, no toggles: chat and code (copy; Python runs in the browser via Pyodide), images and video inline, web answers with their sources, voice in (speech recognition) and read-aloud. - Streams from HAL 8's public Fusion endpoint (hal8.odyssey-works.io/v1/public/fusion/chat); the browser never holds a key. Limits come back as a friendly "see you tomorrow" card. - A small safe markdown renderer: everything escaped, https-only links and media, HAL 8-relative file links resolved against HAL 8. - tools/fusion_inject.py replaces the old assistant block idempotently (between /*F8-BEGIN*/ and /*F8-END*/) and inlines fusion/fusion.css. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
67
tools/fusion_inject.py
Normal file
67
tools/fusion_inject.py
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Put Fusion AI (powered by HAL 8) into the hub, replacing the old assistant pane.
|
||||
|
||||
python3 tools/fusion_inject.py
|
||||
|
||||
The widget itself is fusion/fusion.js (served as a file, loaded on demand) and fusion/fusion.css
|
||||
(inlined into the bundle). The old block, from its "FUSION AI — assistant pane" banner to the end of
|
||||
the FusionAI component, is replaced by a small component between /*F8-BEGIN*/ and /*F8-END*/;
|
||||
re-running replaces that block and the style block again, so the script is idempotent.
|
||||
The endpoint is HAL 8's public Fusion route; window.FUSION_AI_ENDPOINT still overrides it.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SITE = Path(__file__).resolve().parents[1]
|
||||
ENDPOINT = "https://hal8.odyssey-works.io/v1/public/fusion/chat"
|
||||
tool = SITE / "tools" / "bundle.py"
|
||||
tmp = SITE / "tools" / "_page.html"
|
||||
subprocess.run([sys.executable, str(tool), "decode", str(SITE / "index.html"), str(tmp)], check=True, capture_output=True)
|
||||
page = tmp.read_text("utf-8")
|
||||
|
||||
VER = hashlib.sha1((SITE / "fusion" / "fusion.js").read_bytes()).hexdigest()[:10]
|
||||
COMPONENT = f"""/*F8-BEGIN*/
|
||||
// ============================================================================
|
||||
// FUSION AI — powered by HAL 8 (fusion/fusion.js; the key lives on HAL 8, never here)
|
||||
// ============================================================================
|
||||
function FusionAI() {{
|
||||
const ref = useRef(null);
|
||||
useEffect(() => {{
|
||||
let api = null, dead = false;
|
||||
import("./fusion/fusion.js?v={VER}")
|
||||
.then(m => {{ if (!dead) api = m.mount(ref.current, {{ endpoint: window.FUSION_AI_ENDPOINT || "{ENDPOINT}" }}); }})
|
||||
.catch(e => console.warn("[Fusion AI]", e));
|
||||
return () => {{ dead = true; if (api) api.destroy(); }};
|
||||
}}, []);
|
||||
return MG("div", {{ ref }});
|
||||
}}
|
||||
/*F8-END*/
|
||||
"""
|
||||
|
||||
if "/*F8-BEGIN*/" in page:
|
||||
i = page.index("/*F8-BEGIN*/")
|
||||
j = page.index("/*F8-END*/\n", i) + len("/*F8-END*/\n")
|
||||
else:
|
||||
banner = page.index("// FUSION AI — assistant pane")
|
||||
i = page.rfind("// ====", 0, banner)
|
||||
f = page.index("function FusionAI()", banner)
|
||||
j = re.compile(r"\n}\n").search(page, f).end()
|
||||
old = page[i:j]
|
||||
assert old.count("function ") == 1 and "SYSTEM_PROMPT" in old and "Powered by Claude" in old, "unexpected old block"
|
||||
page = page[:i] + COMPONENT + page[j:]
|
||||
assert "Powered by Claude" not in page and page.count("function FusionAI()") == 1
|
||||
|
||||
css = (SITE / "fusion" / "fusion.css").read_text("utf-8")
|
||||
page = re.sub(r"<style>/\*f8-css-begin\*/.*?/\*f8-css-end\*/</style>\n", "", page, flags=re.S)
|
||||
k = page.rfind("</head>")
|
||||
page = page[:k] + "<style>/*f8-css-begin*/" + css + "/*f8-css-end*/</style>\n" + page[k:]
|
||||
|
||||
tmp.write_text(page, "utf-8")
|
||||
r = subprocess.run([sys.executable, str(tool), "encode", str(SITE / "index.html"), str(tmp), str(SITE / "index.html")], capture_output=True, text=True)
|
||||
tmp.unlink()
|
||||
print(r.stdout.strip() or r.stderr.strip())
|
||||
print(f"fusion.js v{VER}")
|
||||
Reference in New Issue
Block a user