52 lines
2.3 KiB
Python
52 lines
2.3 KiB
Python
"""Editable prompts and validated payload templates."""
|
||
from pathlib import Path
|
||
from string import Template, Formatter
|
||
|
||
import yaml
|
||
from pydantic import model_validator
|
||
from llm.config import ConfigModel
|
||
|
||
DEFAULT_PROMPTS = Path(__file__).resolve().parents[1] / 'prompts.yaml'
|
||
|
||
|
||
class Prompts(ConfigModel):
|
||
teacher_system: str
|
||
teacher_user: str
|
||
teacher_retry: str
|
||
training_system: dict[str, str]
|
||
structured_system: dict[str, str]
|
||
training_user: str
|
||
task_instructions: dict[str, str]
|
||
object_names: dict[str, str]
|
||
action_templates: dict[str, str]
|
||
|
||
@model_validator(mode='after')
|
||
def validate_texts(self):
|
||
texts = [self.teacher_system, *self.training_system.values(), *self.structured_system.values(), *self.task_instructions.values()]
|
||
if any(not text.strip() for text in texts):
|
||
raise ValueError('Промпты не должны быть пустыми')
|
||
if set(self.training_system) != {'full', 'step', 'branch'}:
|
||
raise ValueError('training_system должен содержать full, step, branch')
|
||
if set(self.structured_system) != {'full', 'step', 'branch'}:
|
||
raise ValueError('structured_system должен содержать full, step, branch')
|
||
for value in (self.teacher_user, self.teacher_retry, self.training_user):
|
||
template = Template(value)
|
||
if not template.is_valid() or set(template.get_identifiers()) != {'payload'}:
|
||
raise ValueError('Шаблон должен содержать ${payload}; другие переменные не поддерживаются')
|
||
for value in self.action_templates.values():
|
||
if not value.strip():
|
||
raise ValueError('Пустой шаблон действия')
|
||
fields = {field for _, field, _, _ in Formatter().parse(value) if field is not None}
|
||
if fields - {'object', 'target'}:
|
||
raise ValueError('В action_templates допустимы только {object} и {target}')
|
||
value.format(object='объект', target='место')
|
||
return self
|
||
|
||
|
||
def load_prompts(path: Path = DEFAULT_PROMPTS) -> Prompts:
|
||
return Prompts.model_validate(yaml.safe_load(path.read_text(encoding='utf-8')))
|
||
|
||
|
||
def render(template: str, payload: str) -> str:
|
||
return Template(template).substitute(payload=payload)
|