-
Notifications
You must be signed in to change notification settings - Fork 12.2k
Add example script for rendering jinja2 templates #7246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
eac2e83
gguf: Add example script for extracting chat template
teleprint-me f572213
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me bf5154f
docs: Fix filename in docstring and remove return type from main
teleprint-me 4a018e7
feat: Add assistant turn
teleprint-me 8b9ed88
patch: Handle how templates are rendered if no system prompt is allowed
teleprint-me 668c7ee
refactor: Use render template instead of format
teleprint-me fa0b0b1
feat: Allow toggling verbosity
teleprint-me 6be3576
feat: Add sane defaults and options for setting special tokens
teleprint-me 214e9e6
refactor: Add logging debug and clean up logger implementation
teleprint-me f8bb223
refactor: Remove rename from display to render and return result inst…
teleprint-me da96fdd
patch: Apply patch for advisories/GHSA-56xg-wfcc-g829
teleprint-me cfe659d
feat: Add option for adding generation prompt
teleprint-me b4b6f1f
fix: End messages with a user role due to jinja2 conditional checks
teleprint-me 2185e5c
docs: Update and fix CLI help descriptions
teleprint-me 8b67acc
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me 3c23d9f
Merge branch 'master' into gguf-model-template
teleprint-me 174bb3b
Merge branch 'gguf-model-template' of github.com:teleprint-me/llama.c…
teleprint-me 1b18688
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me 4204cab
chore : Apply snake case as described in #8305
teleprint-me b7528fd
chore : Add jinja2 as dev dependency in pyproject.toml and explicit d…
teleprint-me 0cb404c
feat : Add shebang and executable bit to enable script execution
teleprint-me f455e82
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me 27070de
Merge branch 'master' of github.com:teleprint-me/llama.cpp into gguf-…
teleprint-me 5481cec
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me 6875ace
Merge branch 'gguf-model-template' of github.com:teleprint-me/llama.c…
teleprint-me 0de43fc
chore : Set sentencepiece to 0.2.0 to match requirements.txt
teleprint-me fe88330
chore : Add gguf_template to poetry scripts
teleprint-me a083c6c
chore : Add gguf template entrypoint to scripts sub package and fix t…
teleprint-me 43eef8d
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me 964ee4b
Merge branch 'ggerganov:master' into gguf-model-template
teleprint-me File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
teleprint-me marked this conversation as resolved.
Show resolved
Hide resolved
|
||
gguf_template.py - example file to extract the chat template from the models metadata | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
import argparse | ||
import logging | ||
import os | ||
import sys | ||
from pathlib import Path | ||
|
||
import jinja2 | ||
teleprint-me marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import jinja2.sandbox | ||
|
||
# Necessary to load the local gguf package | ||
if "NO_LOCAL_GGUF" not in os.environ and (Path(__file__).parent.parent.parent / 'gguf-py').exists(): | ||
sys.path.insert(0, str(Path(__file__).parent.parent)) | ||
|
||
from gguf.constants import Keys | ||
from gguf.gguf_reader import GGUFReader # noqa: E402 | ||
|
||
# Configure logging | ||
logger = logging.getLogger("gguf-chat-template") | ||
|
||
|
||
def get_chat_template(model_file: str) -> str: | ||
reader = GGUFReader(model_file) | ||
|
||
# Available keys | ||
logger.debug("Detected model metadata!") | ||
logger.debug("Outputting available model fields:") | ||
for key in reader.fields.keys(): | ||
logger.debug(key) | ||
|
||
# Access the 'chat_template' field directly using its key | ||
chat_template_field = reader.fields.get(Keys.Tokenizer.CHAT_TEMPLATE) | ||
|
||
if chat_template_field: | ||
# Extract the chat template string from the field | ||
chat_template_memmap = chat_template_field.parts[-1] | ||
chat_template_string = chat_template_memmap.tobytes().decode("utf-8") | ||
return chat_template_string | ||
else: | ||
logger.error("Chat template field not found in model metadata.") | ||
return "" | ||
|
||
|
||
def render_chat_template( | ||
chat_template: str, | ||
bos_token: str, | ||
eos_token: str, | ||
add_generation_prompt: bool = False, | ||
render_template: bool = False, | ||
) -> str: | ||
""" | ||
Display the chat template to standard output, optionally formatting it using Jinja2. | ||
|
||
Args: | ||
chat_template (str): The extracted chat template. | ||
render_template (bool, optional): Whether to format the template using Jinja2. Defaults to False. | ||
""" | ||
logger.debug(f"Render Template: {render_template}") | ||
logger.debug(f"Add Generation Prompt: {add_generation_prompt}") | ||
|
||
if render_template: | ||
# Render the formatted template using Jinja2 with a context that includes 'bos_token' and 'eos_token' | ||
env = jinja2.sandbox.ImmutableSandboxedEnvironment( | ||
trim_blocks=True, lstrip_blocks=True | ||
) | ||
template = env.from_string(chat_template) | ||
|
||
messages = [ | ||
{"role": "system", "content": "I am a helpful assistant."}, | ||
{"role": "user", "content": "Hello!"}, | ||
{"role": "assistant", "content": "Hello! How may I assist you today?"}, | ||
{"role": "user", "content": "Can you tell me what pickled mayonnaise is?"}, | ||
{"role": "assistant", "content": "Certainly! What would you like to know about it?"}, | ||
{"role": "user", "content": "Is it just regular mayonnaise with vinegar or something else?"}, | ||
] | ||
|
||
try: | ||
formatted_template = template.render( | ||
messages=messages, | ||
bos_token=bos_token, | ||
eos_token=eos_token, | ||
add_generation_prompt=add_generation_prompt, | ||
) | ||
except jinja2.exceptions.UndefinedError: | ||
# system message is incompatible with set format | ||
formatted_template = template.render( | ||
messages=messages[1:], | ||
bos_token=bos_token, | ||
eos_token=eos_token, | ||
add_generation_prompt=add_generation_prompt, | ||
) | ||
|
||
return formatted_template | ||
else: | ||
# Display the raw template | ||
return chat_template | ||
|
||
|
||
# Example usage: | ||
def main(): | ||
parser = argparse.ArgumentParser( | ||
description="Extract chat template from a GGUF model file" | ||
) | ||
parser.add_argument("model_file", type=str, help="Path to the GGUF model file") | ||
parser.add_argument( | ||
"-r", | ||
"--render-template", | ||
action="store_true", | ||
help="Render the chat template using Jinja2. Default is False.", | ||
) | ||
parser.add_argument( | ||
"-b", | ||
"--bos", | ||
default="<s>", | ||
help="Set a bos special token. Default is '<s>'.", | ||
) | ||
parser.add_argument( | ||
"-e", | ||
"--eos", | ||
default="</s>", | ||
help="Set a eos special token. Default is '</s>'.", | ||
) | ||
parser.add_argument( | ||
"-g", | ||
"--agp", | ||
action="store_true", | ||
help="Add generation prompt. Default is False.", | ||
) | ||
parser.add_argument( | ||
"-v", | ||
"--verbose", | ||
action="store_true", | ||
help="Output model keys. Default is False.", | ||
) | ||
args = parser.parse_args() | ||
|
||
if args.verbose: | ||
logging.basicConfig(level=logging.DEBUG) | ||
else: | ||
logging.basicConfig(level=logging.INFO) | ||
|
||
chat_template = get_chat_template(args.model_file) | ||
rendered_template = render_chat_template( | ||
chat_template, | ||
args.bos, | ||
args.eos, | ||
add_generation_prompt=args.agp, | ||
render_template=args.render_template, | ||
) | ||
print(rendered_template) # noqa: NP100 | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.