29 lines
900 B
Python
29 lines
900 B
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
PROMPT_ROOT = Path(__file__).resolve().parent.parent / "prompts"
|
|
_TOKEN_RE = re.compile(r"{{\s*([A-Za-z_][A-Za-z0-9_]*)\s*}}")
|
|
|
|
|
|
def load_prompt_template(relative_path: str) -> str:
|
|
path = (PROMPT_ROOT / relative_path).resolve()
|
|
if not path.is_relative_to(PROMPT_ROOT.resolve()):
|
|
raise ValueError(f"Invalid prompt path: {relative_path}")
|
|
return path.read_text(encoding="utf-8")
|
|
|
|
|
|
def render_prompt_template(template: str, **context: Any) -> str:
|
|
def _replace(match: re.Match[str]) -> str:
|
|
value = context.get(match.group(1), "")
|
|
return "" if value is None else str(value)
|
|
|
|
return _TOKEN_RE.sub(_replace, template)
|
|
|
|
|
|
def render_prompt(relative_path: str, **context: Any) -> str:
|
|
return render_prompt_template(load_prompt_template(relative_path), **context)
|