comms(atlasbot): respond to @atlas mentions and keep context
This commit is contained in:
parent
f18f1df1ce
commit
2d8540907a
@ -5,7 +5,7 @@ metadata:
|
|||||||
name: atlasbot
|
name: atlasbot
|
||||||
data:
|
data:
|
||||||
bot.py: |
|
bot.py: |
|
||||||
import json, os, time, collections
|
import json, os, time, collections, re
|
||||||
from urllib import request, parse, error
|
from urllib import request, parse, error
|
||||||
|
|
||||||
BASE = os.environ.get("MATRIX_BASE", "http://othrys-synapse-matrix-synapse:8008")
|
BASE = os.environ.get("MATRIX_BASE", "http://othrys-synapse-matrix-synapse:8008")
|
||||||
@ -16,6 +16,9 @@ data:
|
|||||||
OLLAMA_URL = os.environ.get("OLLAMA_URL", "https://chat.ai.bstein.dev/")
|
OLLAMA_URL = os.environ.get("OLLAMA_URL", "https://chat.ai.bstein.dev/")
|
||||||
MODEL = os.environ.get("OLLAMA_MODEL", "qwen2.5-coder:7b-instruct-q4_0")
|
MODEL = os.environ.get("OLLAMA_MODEL", "qwen2.5-coder:7b-instruct-q4_0")
|
||||||
API_KEY = os.environ.get("CHAT_API_KEY", "")
|
API_KEY = os.environ.get("CHAT_API_KEY", "")
|
||||||
|
BOT_MENTIONS = os.environ.get("BOT_MENTIONS", f"{USER},atlas")
|
||||||
|
MENTION_LOCALPARTS = [m.strip().lstrip("@") for m in BOT_MENTIONS.split(",") if m.strip()]
|
||||||
|
MENTION_RE = re.compile(r"(?<!\\w)@(?:" + "|".join(re.escape(m) for m in MENTION_LOCALPARTS) + r")(?:\\:[^\\s]+)?(?!\\w)", re.IGNORECASE)
|
||||||
|
|
||||||
def req(method: str, path: str, token: str | None = None, body=None, timeout=60, base: str | None = None):
|
def req(method: str, path: str, token: str | None = None, body=None, timeout=60, base: str | None = None):
|
||||||
url = (base or BASE) + path
|
url = (base or BASE) + path
|
||||||
@ -52,12 +55,19 @@ data:
|
|||||||
path = f"/_matrix/client/v3/rooms/{parse.quote(room)}/send/m.room.message"
|
path = f"/_matrix/client/v3/rooms/{parse.quote(room)}/send/m.room.message"
|
||||||
req("POST", path, token, body={"msgtype": "m.text", "body": text})
|
req("POST", path, token, body={"msgtype": "m.text", "body": text})
|
||||||
|
|
||||||
history = collections.defaultdict(list) # room_id -> list of str (short transcript)
|
history = collections.defaultdict(list) # (room_id, sender|None) -> list of str (short transcript)
|
||||||
|
|
||||||
def ollama_reply(room_id: str, prompt: str) -> str:
|
def key_for(room_id: str, sender: str, is_dm: bool):
|
||||||
|
return (room_id, None) if is_dm else (room_id, sender)
|
||||||
|
|
||||||
|
def ollama_reply(hist_key, prompt: str) -> str:
|
||||||
try:
|
try:
|
||||||
# Keep short context as plain text transcript
|
# Keep short context as plain text transcript
|
||||||
transcript = "\n".join(history[room_id][-12:] + [f"User: {prompt}"])
|
transcript = "\n".join(
|
||||||
|
["System: You are Atlas, the Titan lab assistant for Othrys. Be helpful, direct, and concise."]
|
||||||
|
+ history[hist_key][-24:]
|
||||||
|
+ [f"User: {prompt}"]
|
||||||
|
)
|
||||||
payload = {"model": MODEL, "message": transcript}
|
payload = {"model": MODEL, "message": transcript}
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
if API_KEY:
|
if API_KEY:
|
||||||
@ -66,7 +76,7 @@ data:
|
|||||||
with request.urlopen(r, timeout=15) as resp:
|
with request.urlopen(r, timeout=15) as resp:
|
||||||
data = json.loads(resp.read().decode())
|
data = json.loads(resp.read().decode())
|
||||||
reply = data.get("message") or data.get("response") or data.get("reply") or "I'm here to help."
|
reply = data.get("message") or data.get("response") or data.get("reply") or "I'm here to help."
|
||||||
history[room_id].append(f"Atlas: {reply}")
|
history[hist_key].append(f"Atlas: {reply}")
|
||||||
return reply
|
return reply
|
||||||
except Exception:
|
except Exception:
|
||||||
return "Hi! I'm Atlas."
|
return "Hi! I'm Atlas."
|
||||||
@ -113,10 +123,12 @@ data:
|
|||||||
# Only respond if bot is mentioned or in a DM
|
# Only respond if bot is mentioned or in a DM
|
||||||
joined_count = data.get("summary", {}).get("m.joined_member_count")
|
joined_count = data.get("summary", {}).get("m.joined_member_count")
|
||||||
is_dm = joined_count is not None and joined_count <= 2
|
is_dm = joined_count is not None and joined_count <= 2
|
||||||
mentioned = f"@{USER}" in body
|
mentioned = MENTION_RE.search(body) is not None
|
||||||
history[rid].append(f"{sender}: {body}")
|
hist_key = key_for(rid, sender, is_dm)
|
||||||
|
history[hist_key].append(f"{sender}: {body}")
|
||||||
|
history[hist_key] = history[hist_key][-80:]
|
||||||
if is_dm or mentioned:
|
if is_dm or mentioned:
|
||||||
reply = ollama_reply(rid, body)
|
reply = ollama_reply(hist_key, body)
|
||||||
send_msg(token, rid, reply)
|
send_msg(token, rid, reply)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user