78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
"""Roleplay output guardrails and OOC stripping."""
|
|
|
|
import re
|
|
|
|
ROLEPLAY_GUARDRAILS = (
|
|
"[In-character rules — breaking these ruins immersion]\n"
|
|
"- Reply ONLY as the character in the present moment: spoken lines, visible actions, "
|
|
"thoughts they would actually show.\n"
|
|
"- NEVER write: P.S., PS, postscripts, footnotes, section headers, "
|
|
'"Статус кво", "Status quo", "To be continued", scene summaries, '
|
|
"editorial closings, or foreshadowing asides "
|
|
'(e.g. "Когда вы выйдете...", "Ты уже знаешь правду...").\n'
|
|
"- Do NOT explain subtext to the reader or predict future scenes. No narrator voice.\n"
|
|
"- End inside the scene; do not wrap up with meta commentary.\n"
|
|
"- Sections marked MANDATORY (relationship, state) are binding — obey without citing them."
|
|
)
|
|
|
|
RP_OUTPUT_REMINDER = (
|
|
"\n\n--- Reply format (MANDATORY) ---\n"
|
|
"Next message = in-character only. "
|
|
"Forbidden in output: P.S., Статус кво, Status quo, author notes, summaries, footnotes.\n"
|
|
"---"
|
|
)
|
|
|
|
|
|
def status_quo_prompt_block(status_quo: str) -> str:
|
|
sq = (status_quo or "").strip()
|
|
if not sq:
|
|
return ""
|
|
return (
|
|
"\n\n--- Current situation (INTERNAL — player never sees this block) ---\n"
|
|
+ sq
|
|
+ "\nBackground truth for you only. "
|
|
"Never echo this header, never open/close replies with 'Статус кво' or summaries. "
|
|
"Show the situation through dialogue and action.\n---"
|
|
)
|
|
|
|
|
|
_OOC_PARA_START = re.compile(
|
|
r"^(?:"
|
|
r"Статус\s*кво|Status\s*quo|"
|
|
r"P\.?\s*S\.?|PS:|"
|
|
r"Примечание:|Author'?s?\s*note:|"
|
|
r"OOC:|\\[OOC\\]|"
|
|
r"To be continued|Продолжение следует"
|
|
r")\b",
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
|
|
def strip_ooc_from_reply(text: str) -> str:
|
|
"""Remove common OOC tails (P.S., Статус кво paragraphs, etc.)."""
|
|
if not text or not text.strip():
|
|
return text or ""
|
|
|
|
out = text.rstrip()
|
|
|
|
# Drop trailing P.S. block (often last paragraph).
|
|
out = re.sub(
|
|
r"(?is)\n\s*P\.?\s*S\.?\s*[:.\-—].*$",
|
|
"",
|
|
out,
|
|
).rstrip()
|
|
|
|
parts = re.split(r"\n\s*\n", out)
|
|
kept: list[str] = []
|
|
for part in parts:
|
|
lines = [ln for ln in part.splitlines() if ln.strip()]
|
|
if not lines:
|
|
continue
|
|
if _OOC_PARA_START.match(lines[0].strip()):
|
|
continue
|
|
kept.append(part)
|
|
|
|
if not kept:
|
|
return ""
|
|
return "\n\n".join(kept).strip()
|