Post-process rendered Jinja2 templates and compile them into OpenAI messages
Project description
prompt-template-to-messages
Turn richly annotated Jinja2 prompts into OpenAI-compatible message payloads without giving up the ergonomics of plain text version control.
Why this project exists
Most prompt repositories still manage prompts as plain text. Diffing, reviewing, and versioning become easy, but multimodal prompts are hard to author and ship. prompt-template-to-messages embraces templates: you keep a single text file that mixes roles, function calls, and rich metadata via helper functions, which render into HTML-like tags prefixed with pt2m-. Under the hood, we combine Jinja2 for rendering dynamic content and BeautifulSoup-powered parsing to compile the result into the structured messages array required by OpenAI-compatible APIs. Welcome to the template era.
Key features
- Author prompts once and render them as OpenAI
messages. - Keep prompts in Git-friendly text files while supporting multimodal content.
- Compose translators to customize how tags produce message fragments.
- Strict rendering: Jinja2 runs with
StrictUndefinedso missing variables fail fast.
Install
pip install prompt-template-to-messages
Quick start
-
Create a template file
welcome.pt2m.jinja:{% set user_name = user_name or "friend" %} {% call _pt2m_message('system') %} You are a concise onboarding assistant. {% endcall %} {% call _pt2m_message('user') %} Hello, {{ user_name }}! {{ _pt2m_resolve_image(intro_image_url, alt='Welcome illustration') }} {% endcall %} -
Render it with Python:
from prompt_template_to_messages import compile_prompt_to_messages template_text = open("welcome.pt2m.jinja", "r", encoding="utf-8").read() messages = compile_prompt_to_messages( template_text, scope={"user_name": "Ada", "intro_image_url": "https://example.com/welcome.png"}, )
-
Send
messagesto your favorite chat completion client.
Examples
Image-only broadcast
Use a scope variable to supply an image URL and render a message that contains only image_url content:
template
{% call _pt2m_message('user') -%}
{{ _pt2m_resolve_image(hero_image, detail='high') }}
{%- endcall %}
scope
scope = {"hero_image": "https://cdn.example/hero.png"}
messages = compile_prompt_to_messages(template, scope=scope)
# -> [{'role': 'user', 'content': [{'type': 'image_url', 'image_url': {'url': 'https://cdn.example/hero.png', 'detail': 'high'}}]}]
Custom translator with plain tags
Plain HTML-like tags that appear in the rendered template can be whitelisted by registering translators. The example below mixes _pt2m_ helpers with a scope function that emits <multi-modal> tags:
from prompt_template_to_messages import compile_prompt_to_messages
template = """{% call _pt2m_message('assistant') -%}Gallery incoming: {{ render_multi_modal(featured) }}{%- endcall %}"""
def render_multi_modal(asset):
return f'<multi-modal ref="{asset["ref"]}" caption="{asset["caption"]}" detail="{asset["detail"]}" />'
def multi_modal_translator(tag, context):
return {
"type": "multi-modal",
"multi_modal": {
"ref": tag.attrs.get("ref"),
"caption": tag.attrs.get("caption"),
"detail": tag.attrs.get("detail"),
},
}
scope = {"featured": {"ref": "hero.png", "caption": "Hero", "detail": "medium"}, "render_multi_modal": render_multi_modal}
messages = compile_prompt_to_messages(template, scope=scope, translators=[("multi-modal", multi_modal_translator)])
Any translator added through translators=[...] is treated as part of the whitelist, so its tag will be parsed even without the pt2m- prefix.
CLI usage
This package ships a CLI named ptm.
ptm render TEMPLATE_PATH --scope scope.json --output messages.json
--scope accepts a JSON file, and --output writes the compiled messages. Run ptm --help for all options.
Formatting and release workflow
The Makefile encodes the recommended workflow:
make formatrunsruff formatonsrc/andtests/.make git-pushformats your code before pushing.make releaseformats, tests, lints, type-checks, builds, and then tags the release.
Contributing
- Clone the repo and run
make install-dev. - Use
make format,make lint, andmake testwhile iterating. - Before pushing, run
make git-pushto enforce formatting. - For publishing, follow
make releaseandmake upload.
License
MIT Licensed. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pt2m-0.1.0.tar.gz.
File metadata
- Download URL: pt2m-0.1.0.tar.gz
- Upload date:
- Size: 9.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08f60e0be9960beeee0c2a28df2399b46a0476f82fc2eaf5ad81dc135d573d68
|
|
| MD5 |
2c2c73ba075176c95cc08dd8950d5d64
|
|
| BLAKE2b-256 |
eca06e60b32837ed15466159f5092be570e54c9ef30a668cd727b897d713353c
|
File details
Details for the file pt2m-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pt2m-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc42eb6303a72774cee6cdf5b56272a246ec04444abd1eb939713ad10214ee41
|
|
| MD5 |
b63dbb35ada6ad37a29c2dfec50e1ecf
|
|
| BLAKE2b-256 |
2428af2f7d19bfc0fd0b943a65c98c1638a1de0b5ea312fb0233a1d82b12a9b4
|