Cleaning things up

This commit is contained in:
DazedAnon 2026-07-11 12:24:34 -05:00
parent 92a336d32d
commit b91d5b9acd
10 changed files with 81 additions and 58 deletions

View file

@ -177,7 +177,12 @@ Format: Japanese name, English name in parentheses, then gender.
> **Note:** A very large vocab file can increase API costs and potentially reduce quality. Focus on the most important characters and terms. > **Note:** A very large vocab file can increase API costs and potentially reduce quality. Focus on the most important characters and terms.
### data/skills/system.md ### data/skills/system.md
This is the system prompt skill sent to the AI on every translation call. A default `data/skills/system.md` is included and works well for most games. You generally don't need to edit it unless you want to customize the translation style. Per-game voice rules go in `<game>/skills/quirks.md` instead. This is the system prompt skill sent to the AI on every translation call. A default `data/skills/system.md` is included and works well for most games. You generally don't need to edit it unless you want to customize the translation style.
Per-game overlays (when a game folder is selected in Workflow) live next to the game:
- `<game>/skills/game.md` - Translation Frame (theme / era / register / naming)
- `<game>/skills/quirks.md` - cross-cutting voice habits
- optional extra `<game>/skills/*.md` custom overlays
--- ---

View file

@ -22,13 +22,13 @@ Regenerate mode: if the user asks for only one block (`glossary`, `speakers`, `t
| `glossary` | Named characters (gender, role, **per-character** speech register) + worldbuilding terms | Global dialect / person rules; honorific policy; speaker-format flags; formatting | | `glossary` | Named characters (gender, role, **per-character** speech register) + worldbuilding terms | Global dialect / person rules; honorific policy; speaker-format flags; formatting |
| `speakers` | Tool flag ENABLE/SKIP + short evidence | Character bios; quirks; full glossary | | `speakers` | Tool flag ENABLE/SKIP + short evidence | Character bios; quirks; full glossary |
| `translation_quirks` | Cross-cutting voice rules (battle-log person, global dialect, item-description style, **unusual** honorific habits) | Per-character register; "always keep -san" (tool base prompt already does); codes/wrap/line counts; speaker flags | | `translation_quirks` | Cross-cutting voice rules (battle-log person, global dialect, item-description style, **unusual** honorific habits) | Per-character register; "always keep -san" (tool base prompt already does); codes/wrap/line counts; speaker flags |
| `game_skill` | **Translation Frame** (theme / era / register / naming / optional myth), pointer to `skills/quirks.md`, tool boundaries | File inventories; verbatim quirks; verbatim glossary; per-character register; restating base honorific/formatting policy | | `game_skill` | **Translation Frame** for the API (theme / era / register / naming / optional myth) saved at `skills/game.md` | File inventories; quirks bullets; glossary; per-character register; IDE scaffolding; restating base honorific/formatting policy |
Hard rules: Hard rules:
1. Per-character voice → `glossary` only. 1. Per-character voice → `glossary` only.
2. Category-wide / cross-cutting voice → `translation_quirks` only. 2. Category-wide / cross-cutting voice → `translation_quirks` only.
3. Default honorifics policy is owned by the tool base prompt - only note **unusual** honorific habits in quirks. 3. Default honorifics policy is owned by the tool base prompt - only note **unusual** honorific habits in quirks.
4. `game_skill` **references** `skills/quirks.md` only; do not reprint those rules or cite legacy names like `translation_quirks.txt`. 4. `game_skill` is the title's Translation Frame for the translation API - keep it compact; do not reprint quirks or glossary.
5. `speakers` is config, not lore. 5. `speakers` is config, not lore.
--- ---
@ -98,25 +98,26 @@ Output as short imperative bullets suitable to paste into `skills/quirks.md`.
### Game skill rules (for `game_skill` block) ### Game skill rules (for `game_skill` block)
Produce a durable IDE skill for this title saved at `skills/translation.md`. Produce the per-game translation skill saved at `skills/game.md`.
DazedMTLTool **merges this file into the translation system prompt** (before quirks).
**Translation Frame** (required section - one compact line per field; evidence-based only): **Translation Frame only** (one compact line per field; evidence-based):
- `世界観 (Theme / setting)` - genre, world type, core atmosphere - `世界観 (Theme / setting)` - genre, world type, core atmosphere
- `時代感 (Era / technology level)` - medieval / modern / sci-fi / historical / etc. - `時代感 (Era / technology level)` - medieval / modern / sci-fi / historical / etc.
- `文体方針 (Register policy)` - overall English style (plain RPG, mythic, courtly, modern casual, military, gothic, …) - `文体方針 (Register policy)` - overall English style (plain RPG, mythic, courtly, modern casual, military, gothic, …)
- `固有名詞方針 (Naming policy)` - invented names, titles, ranks, honorifics, myth-derived terms (high-level only; default honorific keep-policy stays in the tool base prompt) - `固有名詞方針 (Naming policy)` - invented names, titles, ranks, honorifics, myth-derived terms (high-level only; default honorific keep-policy stays in the tool base prompt)
- `神話・伝承 (Myth / folklore basis)` - **omit unless** evidence supports a specific tradition or source family - `神話・伝承 (Myth / folklore basis)` - **omit unless** evidence supports a specific tradition or source family
Also include: Do **not** include:
- **Voice rules** - pointer only to ``skills/quirks.md`` (authoritative) - Voice-rules pointers, tool-boundary essays, or IDE instructions
- **Tool boundaries** - codes/formatting owned by the tool; do not reprint quirks or glossary - Repo file inventories / "files that matter"
- Do **not** list repo files / "files that matter" - Per-character register (glossary) or battle-log / dialect bullets (quirks)
- Do **not** put per-character register here (glossary) or battle-log / dialect bullets here (quirks) - Verbatim quirks or glossary entries
**Path names (required):** **Paths:**
- Voice quirks file: ``skills/quirks.md`` (never ``translation_quirks.txt`` or any other legacy name) - Game skill (API): ``skills/game.md``
- This IDE skill file: ``skills/translation.md`` - Quirks (API): ``skills/quirks.md`` (never ``translation_quirks.txt``)
- Optional user overlays (if mentioned): other ``skills/*.md`` files except ``quirks.md`` / ``translation.md`` - Optional custom API overlays: other ``skills/*.md`` except those two
<!-- /engine:rpgmaker --> <!-- /engine:rpgmaker -->
@ -173,12 +174,10 @@ Label the fence language as `translation_quirks`. Inside: imperative bullet list
### Block `game_skill` ### Block `game_skill`
Label the fence language as `game_skill`. Inside: full markdown for `skills/translation.md`. Label the fence language as `game_skill`. Inside: markdown for `skills/game.md` (Translation Frame only).
Required skeleton (fill in the blanks; keep the Voice rules path exactly):
```markdown ```markdown
# <Game title> - Translation skill # <Game title> - Translation Frame
## Translation Frame ## Translation Frame
世界観 (Theme / setting) - <one compact line> 世界観 (Theme / setting) - <one compact line>
@ -186,15 +185,6 @@ Required skeleton (fill in the blanks; keep the Voice rules path exactly):
文体方針 (Register policy) - <one compact line> 文体方針 (Register policy) - <one compact line>
固有名詞方針 (Naming policy) - <one compact line> 固有名詞方針 (Naming policy) - <one compact line>
神話・伝承 (Myth / folklore basis) - <one compact line, or omit this line entirely if unsupported> 神話・伝承 (Myth / folklore basis) - <one compact line, or omit this line entirely if unsupported>
## Voice rules
Follow `skills/quirks.md` as the authoritative cross-cutting voice guide for this title.
Do not invent alternate quirk filenames.
## Tool boundaries
- DazedMTLTool owns formatting codes, wrap, line counts, and honorifics defaults via its base system skill.
- Per-character register lives in the glossary (`vocab.txt`), not here.
- Do not reprint quirks or glossary entries in this file.
``` ```
If known speakers were prepended in a `<known_speakers>` block above this skill, prefer those names in the glossary, then cross-check Actors.json for other major named actors. If known speakers were prepended in a `<known_speakers>` block above this skill, prefer those names in the glossary, then cross-check Actors.json for other major named actors.

View file

@ -59,8 +59,8 @@ class SkillsTab(QWidget):
intro = QLabel( intro = QLabel(
"Tool-level AI instructions live here. " "Tool-level AI instructions live here. "
"Per-game quirks, the game IDE skill, and optional custom skills are edited " "Per-game quirks, Translation Frame (game skill), and optional custom skills are edited "
"in Workflow Step 2 (they travel with the game folder)." "in Workflow Step 2 (they travel with the game folder and merge into the API prompt)."
) )
intro.setWordWrap(True) intro.setWordWrap(True)
intro.setStyleSheet(_HINT_STYLE) intro.setStyleSheet(_HINT_STYLE)

View file

@ -3018,7 +3018,7 @@ class TranslationTab(QWidget):
except Exception: except Exception:
pass pass
# Per-game quirks overlay: Workflow Step 0 folder → DAZED_GAME_ROOT # Per-game overlays (game.md / quirks / custom): Workflow folder → DAZED_GAME_ROOT
try: try:
game_root = "" game_root = ""
if self.settings: if self.settings:

View file

@ -445,10 +445,10 @@ _STEP_HELP: dict[int, str] = {
"• <code>translation_quirks</code> → Quirks tab " "• <code>translation_quirks</code> → Quirks tab "
"(<code>skills/quirks.md</code>)<br>" "(<code>skills/quirks.md</code>)<br>"
"• <code>game_skill</code> → Game skills → translation tab " "• <code>game_skill</code> → Game skills → translation tab "
"(<code>skills/translation.md</code>)<br><br>" "(<code>skills/game.md</code> - Translation Frame, merged into the API prompt)<br><br>"
"Optional: <b>+</b> on Game skills adds custom <code>skills/*.md</code> " "Optional: <b>+</b> on Game skills adds custom <code>skills/*.md</code> "
"overlays (merged into the API prompt - can hurt quality; use sparingly).<br><br>" "overlays (also merged into the API prompt - can hurt quality; use sparingly).<br><br>"
"Use one game folder per translation run so quirks stay in the prompt cache." "Use one game folder per translation run so frame/quirks stay in the prompt cache."
), ),
3: ( 3: (
"<b>Step 3 - TL Phase 1</b><br><br>" "<b>Step 3 - TL Phase 1</b><br><br>"
@ -1793,7 +1793,7 @@ class WorkflowTab(QWidget):
"Quirks", "Quirks",
) )
# Game skills: built-in translation.md + optional custom overlays # Game skills: built-in game.md + optional custom overlays
game_skills_page = QWidget() game_skills_page = QWidget()
gs_layout = QVBoxLayout(game_skills_page) gs_layout = QVBoxLayout(game_skills_page)
gs_layout.setContentsMargins(0, 0, 0, 0) gs_layout.setContentsMargins(0, 0, 0, 0)
@ -1845,11 +1845,11 @@ class WorkflowTab(QWidget):
gs_layout.addWidget(self._game_skills_stack, 1) gs_layout.addWidget(self._game_skills_stack, 1)
self._add_game_skill_page( self._add_game_skill_page(
"translation", "game",
_editor_page( _editor_page(
"<game>/skills/translation.md", "<game>/skills/game.md",
"Paste the game_skill block (Translation Frame + voice/tool pointers). " "Paste the game_skill Translation Frame. Merged into the translation "
"IDE companion skill for this game repo (not injected into the API prompt).", "system prompt (before quirks) when this game folder is selected.",
self._save_game_skill, self._save_game_skill,
self._reload_game_skill, self._reload_game_skill,
"game_skill_editor", "game_skill_editor",
@ -2437,7 +2437,7 @@ class WorkflowTab(QWidget):
# Pre-populate all Phase 2 checkboxes from current module state # Pre-populate all Phase 2 checkboxes from current module state
self._populate_p2_checkboxes() self._populate_p2_checkboxes()
# ── Step 5: Plugins/scripts + Export ─────────────────────────────────── # ── Step 5: Plugins.js + Export ────────────────────────────────────────
def _build_step5_finish(self, layout: QVBoxLayout): def _build_step5_finish(self, layout: QVBoxLayout):
self._add_step_header(layout, "Step 5 — Plugins & Export", 5) self._add_step_header(layout, "Step 5 — Plugins & Export", 5)
@ -3692,7 +3692,7 @@ class WorkflowTab(QWidget):
if bar is None or stack is None: if bar is None or stack is None:
return return
# Remove existing custom tabs (index 0 is always translation). # Remove existing custom tabs (index 0 is always game.md).
while bar.count() > 1: while bar.count() > 1:
bar.removeTab(1) bar.removeTab(1)
while stack.count() > 1: while stack.count() > 1:
@ -3757,8 +3757,8 @@ class WorkflowTab(QWidget):
"<b>Custom skills are merged into the translation system prompt.</b><br><br>" "<b>Custom skills are merged into the translation system prompt.</b><br><br>"
"Extra or poorly written skills can <b>distract the model and hurt " "Extra or poorly written skills can <b>distract the model and hurt "
"translation quality</b> (conflicting rules, prompt bloat, diluted quirks).<br><br>" "translation quality</b> (conflicting rules, prompt bloat, diluted quirks).<br><br>"
"Prefer <code>quirks.md</code> for voice rules and <code>translation.md</code> " "Prefer <code>quirks.md</code> for voice rules and <code>game.md</code> "
"for IDE guidance. Add a custom skill only if you need a rare, tightly scoped " "for the Translation Frame. Add a custom skill only if you need a rare, tightly scoped "
"overlay - <b>at your own risk</b>." "overlay - <b>at your own risk</b>."
) )
warn.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok) warn.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok)
@ -3783,7 +3783,7 @@ class WorkflowTab(QWidget):
self, self,
"Invalid name", "Invalid name",
"Use a short name like battle-log or honorifics_extra.\n" "Use a short name like battle-log or honorifics_extra.\n"
"Reserved: quirks, translation.", "Reserved: quirks, game, translation.",
) )
return return
if stem in self._custom_skill_editors: if stem in self._custom_skill_editors:

View file

@ -251,7 +251,7 @@ def handleMVMZ(filename, estimate):
except Exception: except Exception:
pass pass
# Reload base prompt + optional per-game quirks (DAZED_GAME_ROOT). # Reload system.md + per-game overlays (game.md / quirks / custom) via DAZED_GAME_ROOT.
PROMPT = load_system_prompt() PROMPT = load_system_prompt()
TRANSLATION_CONFIG.prompt = PROMPT TRANSLATION_CONFIG.prompt = PROMPT

View file

@ -154,7 +154,7 @@ def handleWolfDawn(filename, estimate):
# that an earlier Phase 0 (names) harvested into vocab.txt. # that an earlier Phase 0 (names) harvested into vocab.txt.
VOCAB = VOCAB_PATH.read_text(encoding="utf-8") VOCAB = VOCAB_PATH.read_text(encoding="utf-8")
TRANSLATION_CONFIG.vocab = VOCAB TRANSLATION_CONFIG.vocab = VOCAB
# Reload base prompt + optional per-game quirks (DAZED_GAME_ROOT). # Reload system.md + per-game overlays (game.md / quirks / custom) via DAZED_GAME_ROOT.
PROMPT = load_system_prompt() PROMPT = load_system_prompt()
TRANSLATION_CONFIG.prompt = PROMPT TRANSLATION_CONFIG.prompt = PROMPT

View file

@ -20,9 +20,10 @@ TRANSLATION_CONTEXTS_PATH = DATA_DIR / "translation_contexts.json"
# Per-game quirks skill (API overlay). Legacy flat file still migrated on load. # Per-game quirks skill (API overlay). Legacy flat file still migrated on load.
GAME_QUIRKS_RELATIVE = Path("skills") / "quirks.md" GAME_QUIRKS_RELATIVE = Path("skills") / "quirks.md"
LEGACY_QUIRKS_FILENAME = "translation_quirks.txt" LEGACY_QUIRKS_FILENAME = "translation_quirks.txt"
GAME_SKILL_RELATIVE = Path("skills") / "translation.md" GAME_SKILL_RELATIVE = Path("skills") / "game.md"
LEGACY_GAME_SKILL_RELATIVE = Path("skills") / "translation.md"
# Built-in skill filenames under <game>/skills/ (not user-custom overlays). # Built-in skill filenames under <game>/skills/ (not user-custom overlays).
GAME_SKILL_RESERVED_NAMES = frozenset({"quirks.md", "translation.md"}) GAME_SKILL_RESERVED_NAMES = frozenset({"quirks.md", "game.md", "translation.md"})
_ROOT_DATA_FILES = ( _ROOT_DATA_FILES = (
"vocab.txt", "vocab.txt",

View file

@ -1,4 +1,4 @@
"""Load the static system prompt and optional per-game quirks overlay.""" """Load the static system prompt and optional per-game skill overlays."""
from __future__ import annotations from __future__ import annotations
@ -10,12 +10,19 @@ from util.paths import (
GAME_QUIRKS_RELATIVE, GAME_QUIRKS_RELATIVE,
GAME_SKILL_RELATIVE, GAME_SKILL_RELATIVE,
GAME_SKILL_RESERVED_NAMES, GAME_SKILL_RESERVED_NAMES,
LEGACY_GAME_SKILL_RELATIVE,
LEGACY_QUIRKS_FILENAME, LEGACY_QUIRKS_FILENAME,
PROMPT_PATH, PROMPT_PATH,
) )
_SKILL_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$") _SKILL_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$")
# Drop legacy IDE-only sections from older game skill files.
_IDE_SECTION_RE = re.compile(
r"\n## (?:Voice rules|Tool boundaries)\b.*?(?=\n## |\Z)",
re.DOTALL | re.IGNORECASE,
)
def quirks_path_for_game(game_root: str | Path | None) -> Path | None: def quirks_path_for_game(game_root: str | Path | None) -> Path | None:
"""Return ``<game_root>/skills/quirks.md`` when *game_root* is set. """Return ``<game_root>/skills/quirks.md`` when *game_root* is set.
@ -38,27 +45,40 @@ def quirks_path_for_game(game_root: str | Path | None) -> Path | None:
def game_skill_path_for_game(game_root: str | Path | None) -> Path | None: def game_skill_path_for_game(game_root: str | Path | None) -> Path | None:
"""Return ``<game_root>/skills/translation.md`` when *game_root* is set.""" """Return ``<game_root>/skills/game.md`` when *game_root* is set.
Migrates legacy ``skills/translation.md`` to ``skills/game.md`` when needed.
"""
if not game_root: if not game_root:
return None return None
return Path(game_root) / GAME_SKILL_RELATIVE root = Path(game_root)
preferred = root / GAME_SKILL_RELATIVE
legacy = root / LEGACY_GAME_SKILL_RELATIVE
if not preferred.is_file() and legacy.is_file():
preferred.parent.mkdir(parents=True, exist_ok=True)
try:
legacy.rename(preferred)
except OSError:
return legacy
return preferred
def migrate_game_skill_text(text: str) -> str: def migrate_game_skill_text(text: str) -> str:
"""Rewrite legacy quirk path names inside a game skill markdown body.""" """Normalize a game skill body for API use (path fixes + drop IDE scaffolding)."""
if not text: if not text:
return text return text
# Common stale pointers from older Project Setup output. # Common stale pointers from older Project Setup output.
updated = text.replace("translation_quirks.txt", "skills/quirks.md") updated = text.replace("translation_quirks.txt", "skills/quirks.md")
updated = updated.replace("`translation_quirks.md`", "`skills/quirks.md`") updated = updated.replace("`translation_quirks.md`", "`skills/quirks.md`")
# Bare relative quirks.md without skills/ prefix (keep skills/quirks.md intact).
updated = re.sub( updated = re.sub(
r"(?<!skills/)(?<![\w./-])quirks\.md(?![\w.-])", r"(?<!skills/)(?<![\w./-])quirks\.md(?![\w.-])",
"skills/quirks.md", "skills/quirks.md",
updated, updated,
) )
# Avoid double skills/skills/
updated = updated.replace("skills/skills/quirks.md", "skills/quirks.md") updated = updated.replace("skills/skills/quirks.md", "skills/quirks.md")
# Older templates included IDE-only Voice rules / Tool boundaries sections.
updated = _IDE_SECTION_RE.sub("\n", updated)
updated = re.sub(r"\n{3,}", "\n\n", updated).strip() + "\n"
return updated return updated
@ -98,7 +118,7 @@ def custom_skill_path_for_game(
def list_custom_skill_paths(game_root: str | Path | None) -> list[Path]: def list_custom_skill_paths(game_root: str | Path | None) -> list[Path]:
"""List user custom skill markdown files under ``<game>/skills/``. """List user custom skill markdown files under ``<game>/skills/``.
Excludes built-in ``quirks.md`` and ``translation.md``. Excludes built-in ``quirks.md`` and ``game.md`` (and legacy ``translation.md``).
""" """
skills = game_skills_dir(game_root) skills = game_skills_dir(game_root)
if skills is None or not skills.is_dir(): if skills is None or not skills.is_dir():
@ -116,9 +136,10 @@ def list_custom_skill_paths(game_root: str | Path | None) -> list[Path]:
def load_system_prompt(game_root: str | Path | None = None) -> str: def load_system_prompt(game_root: str | Path | None = None) -> str:
"""Load ``data/skills/system.md`` plus optional per-game overlays. """Load ``data/skills/system.md`` plus optional per-game overlays.
Overlay order: Overlay order (when ``DAZED_GAME_ROOT`` / *game_root* is set):
1. ``skills/quirks.md`` (voice quirks) 1. ``skills/game.md`` - Translation Frame / game skill (API)
2. Any other ``skills/*.md`` except ``translation.md`` (custom skills) 2. ``skills/quirks.md`` - cross-cutting voice quirks
3. other ``skills/*.md`` - optional custom overlays
Path resolution order for the game root: Path resolution order for the game root:
1. Explicit *game_root* argument 1. Explicit *game_root* argument
@ -135,6 +156,12 @@ def load_system_prompt(game_root: str | Path | None = None) -> str:
parts = [base.rstrip()] if base.strip() else [] parts = [base.rstrip()] if base.strip() else []
skill_file = game_skill_path_for_game(root)
if skill_file and skill_file.is_file():
skill = migrate_game_skill_text(skill_file.read_text(encoding="utf-8")).strip()
if skill:
parts.append("## Game Translation Frame\n\n" + skill)
quirks_file = quirks_path_for_game(root) quirks_file = quirks_path_for_game(root)
if quirks_file and quirks_file.is_file(): if quirks_file and quirks_file.is_file():
quirks = quirks_file.read_text(encoding="utf-8").strip() quirks = quirks_file.read_text(encoding="utf-8").strip()

View file

@ -1945,7 +1945,7 @@ def createContext(config, subbedText, formatType, history=None):
cache invalidation caused by changing vocabulary matches. cache invalidation caused by changing vocabulary matches.
Cached in static_system: Cached in static_system:
- data/skills/system.md content (plus optional game quirks overlay) - data/skills/system.md content (plus optional game Translation Frame / quirks / custom overlays)
Dynamic in vocab_text: Dynamic in vocab_text:
- only vocab terms found in the current batch text - only vocab terms found in the current batch text