This commit is contained in:
Mikan
2026-06-21 06:12:28 +03:00
parent 4dee4fb0a8
commit e98559a587
29 changed files with 1248 additions and 267 deletions

View File

@@ -56,6 +56,10 @@ DEFAULT_SETTINGS: dict[str, dict[str, Any]] = {
"ui.logo_url": {"value": "/icon.png", "description": "Logo URL"},
"ui.og_image_url": {"value": "", "description": "OpenGraph image URL"},
"admin.setup_token": {"value": "", "description": "Admin setup token"},
"llm.text_replacements": {
"value": [],
"description": "List of {from, to} pairs. Each 'from' substring in LLM scene_text output is replaced with 'to' (can be empty string to remove).",
},
}
# Keys whose values should never be returned to the client in plaintext.
@@ -185,3 +189,24 @@ async def get_admin_setup_token(session: AsyncSession) -> str:
token = secrets.token_urlsafe(16)
await set_setting(session, "admin.setup_token", token)
return token
async def apply_text_replacements(session: AsyncSession, text: str) -> str:
"""Apply llm.text_replacements to a text string.
Each replacement is a dict {from: str, to: str}. The 'from' substring is
replaced with 'to' (which can be empty to remove the substring).
"""
if not text:
return text
replacements = await get_setting(session, "llm.text_replacements")
if not replacements or not isinstance(replacements, list):
return text
for r in replacements:
if not isinstance(r, dict):
continue
frm = r.get("from")
to = r.get("to", "")
if frm and isinstance(frm, str):
text = text.replace(frm, to)
return text

View File

@@ -133,6 +133,41 @@ def time_le(a: str, b: str) -> bool:
return ga.total_minutes() <= gb.total_minutes()
def format_time_human(time_str: str, language: str = "en") -> str:
"""Format a game time string as a human-readable localized string.
Examples:
- "day_1_hour_8""Day 1, 08:00" (en) / "День 1, 08:00" (ru)
- "day_3_hour_14_min_30""Day 3, 14:30" (en) / "День 3, 14:30" (ru)
- "year_2_day_5_hour_12""Year 2, Day 5, 12:00" (en) / "Год 2, День 5, 12:00" (ru)
"""
try:
gt = GameTime.parse(time_str)
except ValueError:
return time_str # return as-is if unparseable
if language == "ru":
parts = []
if gt.year != 1:
parts.append(f"Год {gt.year}")
parts.append(f"День {gt.day}")
if gt.minute:
parts.append(f"{gt.hour:02d}:{gt.minute:02d}")
else:
parts.append(f"{gt.hour:02d}:00")
return ", ".join(parts)
else: # en
parts = []
if gt.year != 1:
parts.append(f"Year {gt.year}")
parts.append(f"Day {gt.day}")
if gt.minute:
parts.append(f"{gt.hour:02d}:{gt.minute:02d}")
else:
parts.append(f"{gt.hour:02d}:00")
return ", ".join(parts)
def summarize_schemas(schemas: Iterable[dict]) -> str:
"""Render a compact human-readable summary of entity schemas for LLM prompts."""
lines: list[str] = []