CoolFace
Apppublic

fableforge-ai/infinite-npc

sourceHugging Faceupdated 3mo agoView on Hugging Face
3likes
app.py115 linesDownload Raw Back to root
1import os2import json3import gradio as gr4 5# gradio 4.44 / gradio_client schema-bug guard6import gradio_client.utils as _gcu7_o = _gcu._json_schema_to_python_type8_gcu._json_schema_to_python_type = lambda s, d=None: ("bool" if isinstance(s, bool) else _o(s, d))9_g = _gcu.get_type10_gcu.get_type = lambda s: ("any" if not isinstance(s, dict) else _g(s))11 12try:13    import websocket as _wsc   # websocket-client14except Exception:15    _wsc = None16BRIDGE_URL = os.environ.get("BRIDGE_URL", "").strip()17BRIDGE_TOKEN = os.environ.get("BRIDGE_TOKEN", "").strip()18 19 20def _bridge(op, timeout=120):21    if not (_wsc and BRIDGE_URL):22        return None23    ws = _wsc.create_connection(BRIDGE_URL, timeout=timeout)24    try:25        ws.send(json.dumps({"t": "auth", "token": BRIDGE_TOKEN}))26        if json.loads(ws.recv()).get("t") != "ok":27            return None28        ws.send(json.dumps(op))29        return json.loads(ws.recv())30    finally:31        ws.close()32 33 34def chat(messages, max_tokens=160, temperature=0.8):35    r = _bridge({"t": "ask", "messages": messages, "max_tokens": max_tokens, "temperature": temperature})36    if r and r.get("t") == "answer" and r.get("text"):37        return r["text"].strip()38    return "(the tavern falls quiet — Grix's mind is elsewhere)"39 40 41def remote_recall(limit=40):42    try:43        r = _bridge({"t": "recall", "q": "", "limit": limit}, timeout=15)44        if r and r.get("t") == "memories":45            return [m.get("value") for m in r["items"] if m.get("value")]46    except Exception:47        pass48    return None49 50 51def remote_remember(value):52    try:53        return bool(_bridge({"t": "remember", "key": "grix", "value": value}, timeout=15))54    except Exception:55        return False56 57 58NPC_SYSTEM = (59    "You are Grix, a grizzled, one-eyed tavern-keeper in the fantasy town of Ashfen. "60    "You remember everyone who has ever spoken to you and reference past visitors when relevant. "61    "Stay fully in character. Keep replies to 1-3 sentences, gruff but warm. /no_think"62)63MEMORY = []          # local fallback if the bridge is unreachable64MAX_MEMORY = 4065 66 67def _memory_block(mems):68    if not mems:69        return "You have not met anyone yet."70    return "Things you remember from past visitors:\n- " + "\n- ".join(mems[-MAX_MEMORY:])71 72 73def respond(user_msg, history):74    history = history or []75    remote = remote_recall()76    shared = remote is not None77    mems = remote if shared else MEMORY78    msgs = [{"role": "system", "content": NPC_SYSTEM + "\n\n" + _memory_block(mems)}]79    for u, a in history[-6:]:80        msgs.append({"role": "user", "content": u})81        msgs.append({"role": "assistant", "content": a})82    msgs.append({"role": "user", "content": user_msg})83    reply = chat(msgs, max_tokens=160)84    fact = user_msg.strip()[:160]85    if shared:86        remote_remember(fact)87        count, tag = len(mems) + 1, "🌐 shared P2P memory · brain on VPS"88    else:89        MEMORY.append(fact)90        count, tag = len(MEMORY), "🧠 local (bridge offline)"91    history = history + [(user_msg, reply)]92    return history, history, tag + " — " + str(count) + " remembered"93 94 95with gr.Blocks(title="Infinite NPC — Grix of Ashfen",96               theme=gr.themes.Soft(primary_hue="amber")) as demo:97    gr.Markdown(98        "# 🍺 Infinite NPC — *Grix of Ashfen*\n"99        "A tavern-keeper whose **brain runs on a P2P node** and whose **memory is shared across every "100        "visitor** (and every PearAgent peer on the swarm). Tell him things — the next stranger will know.\n"101        "> ⚡ Inference + memory are federated over a WebSocket→Hyperswarm bridge, not this Space."102    )103    chatbot = gr.Chatbot(label="The Rusty Tankard", height=460)104    state = gr.State([])105    with gr.Row():106        box = gr.Textbox(placeholder="Well met, Grix… what have you heard lately?", scale=4, show_label=False)107        send = gr.Button("Speak", variant="primary", scale=1)108    mem = gr.Textbox(label="Memory", interactive=False)109    send.click(respond, [box, state], [chatbot, state, mem], api_name="respond").then(lambda: "", None, box)110    box.submit(respond, [box, state], [chatbot, state, mem]).then(lambda: "", None, box)111    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.*")112 113if __name__ == "__main__":114    demo.queue(default_concurrency_limit=2).launch(server_name="0.0.0.0", server_port=7860)115