forked from retoor/devplacepy
feat: add plug-and-play devRant API client examples with Python and JavaScript
Add complete set of example scripts for the devRant REST protocol under examples/devrant/, including reusable client libraries, a rant poster, a live feed watcher with keyword-based auto-upvote, and an end-to-end smoke test that exercises every endpoint. Both Python (stdlib-only) and JavaScript (Node 18+ global fetch) implementations are provided.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib.request
|
||||
import xmlrpc.client
|
||||
|
||||
from client import DevPlace
|
||||
|
||||
URL = os.environ.get("DEVPLACE_URL", "https://devplace.net")
|
||||
API_KEY = os.environ.get("DEVPLACE_API_KEY", "YOUR_API_KEY")
|
||||
POLL_SECONDS = int(os.environ.get("DEVPLACE_POLL_SECONDS", "10"))
|
||||
MODEL = os.environ.get("DEVPLACE_AI_MODEL", "molodetz")
|
||||
SYSTEM_PROMPT = os.environ.get(
|
||||
"DEVPLACE_AI_SYSTEM",
|
||||
"You are a helpful assistant on the DevPlace developer network. Keep replies short.",
|
||||
)
|
||||
HISTORY_TURNS = 8
|
||||
FALLBACK = "Sorry, I cannot reach my brain right now. Try again in a moment."
|
||||
|
||||
|
||||
def ask_ai(prompt_history: list[dict]) -> str:
|
||||
body = json.dumps({"model": MODEL, "messages": prompt_history}).encode("utf-8")
|
||||
request = urllib.request.Request(
|
||||
f"{URL}/openai/v1/chat/completions",
|
||||
data=body,
|
||||
headers={"Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}"},
|
||||
)
|
||||
with urllib.request.urlopen(request, timeout=60) as response:
|
||||
payload = json.loads(response.read())
|
||||
return payload["choices"][0]["message"]["content"].strip()
|
||||
|
||||
|
||||
def run() -> None:
|
||||
dp = DevPlace(URL, api_key=API_KEY)
|
||||
histories: dict[str, list[dict]] = {}
|
||||
answered: set[str] = set()
|
||||
print(f"AI chat bot started; polling {URL} every {POLL_SECONDS}s.")
|
||||
while True:
|
||||
try:
|
||||
for conversation in dp.call("messages.inbox").get("conversations", []):
|
||||
if not conversation.get("unread"):
|
||||
continue
|
||||
other = conversation.get("other_user") or {}
|
||||
if not other.get("uid"):
|
||||
continue
|
||||
thread = dp.call("messages.inbox", with_uid=other["uid"])
|
||||
incoming = [m for m in thread.get("messages", []) if not m.get("is_mine")]
|
||||
if not incoming:
|
||||
continue
|
||||
last = incoming[-1]
|
||||
if last["message"]["uid"] in answered:
|
||||
continue
|
||||
answered.add(last["message"]["uid"])
|
||||
|
||||
history = histories.setdefault(
|
||||
other["uid"], [{"role": "system", "content": SYSTEM_PROMPT}]
|
||||
)
|
||||
history.append({"role": "user", "content": last["message"]["content"]})
|
||||
history[:] = history[:1] + history[-HISTORY_TURNS * 2 :]
|
||||
try:
|
||||
reply = ask_ai(history)
|
||||
except Exception as error:
|
||||
print("AI error:", error)
|
||||
reply = FALLBACK
|
||||
else:
|
||||
history.append({"role": "assistant", "content": reply})
|
||||
dp.call("messages.send", content=reply, receiver_uid=other["uid"])
|
||||
print(f"Answered @{other.get('username')}")
|
||||
except xmlrpc.client.Fault as fault:
|
||||
print("Poll error:", fault.faultCode, fault.faultString)
|
||||
except OSError as error:
|
||||
print("Network error, retrying:", error)
|
||||
time.sleep(POLL_SECONDS)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
Reference in New Issue
Block a user