pocket-dungeon-master / engine_cloud.py
Singh-Santosh's picture
Fix evaluator findings: engine_cloud.py
73f8b08 verified
Raw
History Blame Contribute Delete
2.43 kB
"""
Cloud inference connector for Pocket Dungeon Master.
Streams RPG narrative from the Modal-hosted vLLM backend (OpenAI-compatible).
Configured via environment variables (set as HF Space secrets):
MODAL_BACKEND_URL e.g. https://<workspace>--pocket-dm-backend-serve.modal.run
MODAL_API_KEY the VLLM_API_KEY chosen when deploying the Modal secret
"""
import os
from openai import OpenAI
from engine import load_system_prompt, log_trace
MODAL_BACKEND_URL = os.environ.get(
"MODAL_BACKEND_URL", "https://your-unique-modal-subdomain.modal.run"
)
MODAL_API_KEY = os.environ.get("MODAL_API_KEY", "EMPTY")
MODEL_NAME = os.environ.get("MODEL_NAME", "Qwen/Qwen2.5-3B-Instruct") # tiny ≤4B (Tiny Titan)
_client = OpenAI(
base_url=MODAL_BACKEND_URL.rstrip("/") + "/v1",
api_key=MODAL_API_KEY or "EMPTY",
timeout=120.0,
)
def call_modal_generator(item_id, history_messages):
"""Yields the cumulative narrative text as it streams from the backend."""
messages = [{"role": "system", "content": load_system_prompt(item_id)}]
for msg in history_messages:
role = getattr(msg, "role", None) or (msg.get("role") if isinstance(msg, dict) else None)
content = getattr(msg, "content", None) or (msg.get("content") if isinstance(msg, dict) else None)
if content:
messages.append({"role": role, "content": content})
full_reply_text = ""
try:
stream = _client.chat.completions.create(
model=MODEL_NAME,
messages=messages,
max_tokens=220,
temperature=0.85,
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
if delta:
full_reply_text += delta
yield full_reply_text
except Exception as e:
yield f"⚠️ The artifact's voice falters — the cloud core is unreachable ({e})."
return
# Log the interaction (Sharing is Caring badge / public trace).
try:
last_user = next(
(m["content"] for m in reversed(messages) if m["role"] == "user"), ""
)
log_trace({"item": item_id, "user": last_user, "model": full_reply_text})
except Exception:
pass
def get_combat_keywords():
return ['rage', 'boil', 'heat', 'kill', 'attack', 'shatter', 'fight',
'force', 'mutate', 'scream', 'wield', 'blade', 'potion', 'key']