infinite-npc / app.py
King3Djbl's picture
Brain-over-bridge: inference + memory via VPS/P2P, no local model
5dfb190 verified
Raw
History Blame Contribute Delete
4.9 kB
import os
import json
import gradio as gr
# gradio 4.44 / gradio_client schema-bug guard
import gradio_client.utils as _gcu
_o = _gcu._json_schema_to_python_type
_gcu._json_schema_to_python_type = lambda s, d=None: ("bool" if isinstance(s, bool) else _o(s, d))
_g = _gcu.get_type
_gcu.get_type = lambda s: ("any" if not isinstance(s, dict) else _g(s))
try:
import websocket as _wsc # websocket-client
except Exception:
_wsc = None
BRIDGE_URL = os.environ.get("BRIDGE_URL", "").strip()
BRIDGE_TOKEN = os.environ.get("BRIDGE_TOKEN", "").strip()
def _bridge(op, timeout=120):
if not (_wsc and BRIDGE_URL):
return None
ws = _wsc.create_connection(BRIDGE_URL, timeout=timeout)
try:
ws.send(json.dumps({"t": "auth", "token": BRIDGE_TOKEN}))
if json.loads(ws.recv()).get("t") != "ok":
return None
ws.send(json.dumps(op))
return json.loads(ws.recv())
finally:
ws.close()
def chat(messages, max_tokens=160, temperature=0.8):
r = _bridge({"t": "ask", "messages": messages, "max_tokens": max_tokens, "temperature": temperature})
if r and r.get("t") == "answer" and r.get("text"):
return r["text"].strip()
return "(the tavern falls quiet — Grix's mind is elsewhere)"
def remote_recall(limit=40):
try:
r = _bridge({"t": "recall", "q": "", "limit": limit}, timeout=15)
if r and r.get("t") == "memories":
return [m.get("value") for m in r["items"] if m.get("value")]
except Exception:
pass
return None
def remote_remember(value):
try:
return bool(_bridge({"t": "remember", "key": "grix", "value": value}, timeout=15))
except Exception:
return False
NPC_SYSTEM = (
"You are Grix, a grizzled, one-eyed tavern-keeper in the fantasy town of Ashfen. "
"You remember everyone who has ever spoken to you and reference past visitors when relevant. "
"Stay fully in character. Keep replies to 1-3 sentences, gruff but warm. /no_think"
)
MEMORY = [] # local fallback if the bridge is unreachable
MAX_MEMORY = 40
def _memory_block(mems):
if not mems:
return "You have not met anyone yet."
return "Things you remember from past visitors:\n- " + "\n- ".join(mems[-MAX_MEMORY:])
def respond(user_msg, history):
history = history or []
remote = remote_recall()
shared = remote is not None
mems = remote if shared else MEMORY
msgs = [{"role": "system", "content": NPC_SYSTEM + "\n\n" + _memory_block(mems)}]
for u, a in history[-6:]:
msgs.append({"role": "user", "content": u})
msgs.append({"role": "assistant", "content": a})
msgs.append({"role": "user", "content": user_msg})
reply = chat(msgs, max_tokens=160)
fact = user_msg.strip()[:160]
if shared:
remote_remember(fact)
count, tag = len(mems) + 1, "🌐 shared P2P memory · brain on VPS"
else:
MEMORY.append(fact)
count, tag = len(MEMORY), "🧠 local (bridge offline)"
history = history + [(user_msg, reply)]
return history, history, tag + " — " + str(count) + " remembered"
with gr.Blocks(title="Infinite NPC — Grix of Ashfen",
theme=gr.themes.Soft(primary_hue="amber")) as demo:
gr.Markdown(
"# 🍺 Infinite NPC — *Grix of Ashfen*\n"
"A tavern-keeper whose **brain runs on a P2P node** and whose **memory is shared across every "
"visitor** (and every PearAgent peer on the swarm). Tell him things — the next stranger will know.\n"
"> ⚡ Inference + memory are federated over a WebSocket→Hyperswarm bridge, not this Space."
)
chatbot = gr.Chatbot(label="The Rusty Tankard", height=460)
state = gr.State([])
with gr.Row():
box = gr.Textbox(placeholder="Well met, Grix… what have you heard lately?", scale=4, show_label=False)
send = gr.Button("Speak", variant="primary", scale=1)
mem = gr.Textbox(label="Memory", interactive=False)
send.click(respond, [box, state], [chatbot, state, mem], api_name="respond").then(lambda: "", None, box)
box.submit(respond, [box, state], [chatbot, state, mem]).then(lambda: "", None, box)
gr.Markdown("---\n⬇️ [**Download the model**](https://huggingface.co/King3Djbl/mythos-9b-unhinged)  ·  🧭 [FableForge Nexus](https://huggingface.co/spaces/fableforge-ai/fableforge-nexus)  ·  👻 [Ghost Writer](https://huggingface.co/spaces/fableforge-ai/ghost-writer)  ·  🌳 [Story Tree](https://huggingface.co/spaces/fableforge-ai/semantic-story-tree)  ·  🎭 [Dual-GM](https://huggingface.co/spaces/King3Djbl/dual-gm-simulator)\n\n*Grix's brain runs on a P2P node, not this Space — his memory is shared across every visitor.*")
if __name__ == "__main__":
demo.queue(default_concurrency_limit=2).launch(server_name="0.0.0.0", server_port=7860)