mirror of
https://github.com/oobabooga/textgen.git
synced 2026-07-23 11:20:54 -05:00
Support .jinja/.jinja2 instruction template files in the UI (closes #7517)
This commit is contained in:
@@ -13,7 +13,7 @@ from .errors import InvalidRequestError
|
||||
from .typing import ToolDefinition
|
||||
from .utils import debug_msg
|
||||
from modules.tool_parsing import get_tool_call_id, parse_tool_call, detect_tool_call_format
|
||||
from modules import shared
|
||||
from modules import shared, utils
|
||||
from modules.reasoning import extract_reasoning
|
||||
from modules.chat import (
|
||||
generate_chat_prompt,
|
||||
@@ -31,10 +31,9 @@ from modules.text_generation import decode, encode, generate_reply
|
||||
def load_chat_template_file(filepath):
|
||||
"""Load a chat template from a file path (.jinja, .jinja2, or .yaml/.yml)."""
|
||||
filepath = Path(filepath)
|
||||
ext = filepath.suffix.lower()
|
||||
text = filepath.read_text(encoding='utf-8')
|
||||
if ext in ['.yaml', '.yml']:
|
||||
data = yaml.safe_load(text)
|
||||
if filepath.suffix.lower() in utils.YAML_EXTENSIONS:
|
||||
data = yaml.safe_load(text) or {}
|
||||
return data.get('instruction_template', '')
|
||||
return text
|
||||
|
||||
|
||||
@@ -2767,9 +2767,17 @@ def handle_save_template_click(instruction_template_str):
|
||||
|
||||
def handle_delete_template_click(template):
|
||||
import gradio as gr
|
||||
root = str(shared.user_data_dir / 'instruction-templates') + '/'
|
||||
from modules.utils import TEMPLATE_EXTENSIONS
|
||||
template_dir = shared.user_data_dir / 'instruction-templates'
|
||||
filename = f"{template}.yaml"
|
||||
for ext in TEMPLATE_EXTENSIONS:
|
||||
if (template_dir / f"{template}{ext}").exists():
|
||||
filename = f"{template}{ext}"
|
||||
break
|
||||
|
||||
root = str(template_dir) + '/'
|
||||
return [
|
||||
f"{template}.yaml",
|
||||
filename,
|
||||
root,
|
||||
root,
|
||||
gr.update(visible=True)
|
||||
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
from modules import loaders, metadata_gguf, shared
|
||||
from modules import loaders, metadata_gguf, shared, utils
|
||||
from modules.logging_colors import logger
|
||||
from modules.utils import resolve_model_path
|
||||
|
||||
@@ -397,28 +397,44 @@ def update_gpu_layers_and_vram(loader, model, gpu_layers, ctx_size, cache_type):
|
||||
return f"<div id=\"vram-info\"'>Estimated VRAM to load the model: <span class=\"value\">{vram_usage:.0f} MiB</span></div>"
|
||||
|
||||
|
||||
def load_template_by_name(name):
|
||||
"""Find and load a single instruction template by name. Returns '' if not found."""
|
||||
template_dir = shared.user_data_dir / 'instruction-templates'
|
||||
for ext in utils.TEMPLATE_EXTENSIONS:
|
||||
path = template_dir / f'{name}{ext}'
|
||||
if path.is_file():
|
||||
break
|
||||
else:
|
||||
return ''
|
||||
|
||||
file_contents = path.read_text(encoding='utf-8')
|
||||
if path.suffix in utils.JINJA_EXTENSIONS:
|
||||
return file_contents
|
||||
|
||||
try:
|
||||
data = yaml.safe_load(file_contents) or {}
|
||||
except yaml.YAMLError:
|
||||
logger.warning(f"Failed to parse '{path.name}' as YAML. Treating it as a raw Jinja template. Consider renaming it to '{name}.jinja'.")
|
||||
return file_contents
|
||||
|
||||
if 'instruction_template' in data:
|
||||
return data['instruction_template']
|
||||
elif 'turn_template' in data:
|
||||
return _jinja_template_from_old_format(data)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def load_instruction_template(template):
|
||||
if template == 'None':
|
||||
return ''
|
||||
|
||||
for name in (template, 'Alpaca'):
|
||||
path = shared.user_data_dir / 'instruction-templates' / f'{name}.yaml'
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
file_contents = f.read()
|
||||
except FileNotFoundError:
|
||||
if name == template:
|
||||
logger.warning(f"Instruction template '{template}' not found, falling back to Alpaca")
|
||||
continue
|
||||
result = load_template_by_name(template)
|
||||
if result:
|
||||
return result
|
||||
|
||||
break
|
||||
else:
|
||||
return ''
|
||||
data = yaml.safe_load(file_contents)
|
||||
if 'instruction_template' in data:
|
||||
return data['instruction_template']
|
||||
else:
|
||||
return _jinja_template_from_old_format(data)
|
||||
logger.warning(f"Instruction template '{template}' not found, falling back to Alpaca")
|
||||
return load_template_by_name('Alpaca')
|
||||
|
||||
|
||||
def _jinja_template_from_old_format(params, verbose=False):
|
||||
|
||||
@@ -14,7 +14,6 @@ import traceback
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
import gradio as gr
|
||||
|
||||
from modules import shared, ui, utils
|
||||
@@ -217,26 +216,8 @@ def clean_path(base_path: str, path: str):
|
||||
|
||||
|
||||
def get_instruction_templates():
|
||||
path = shared.user_data_dir / 'instruction-templates'
|
||||
names = set()
|
||||
for ext in ['yaml', 'yml', 'jinja', 'jinja2']:
|
||||
for f in path.glob(f'*.{ext}'):
|
||||
names.add(f.stem)
|
||||
return ['None', 'Chat Template'] + sorted(names, key=utils.natural_keys)
|
||||
|
||||
|
||||
def load_template(name):
|
||||
"""Load a Jinja2 template string from {user_data_dir}/instruction-templates/."""
|
||||
path = shared.user_data_dir / 'instruction-templates'
|
||||
for ext in ['jinja', 'jinja2', 'yaml', 'yml']:
|
||||
filepath = path / f'{name}.{ext}'
|
||||
if filepath.exists():
|
||||
if ext in ['jinja', 'jinja2']:
|
||||
return filepath.read_text(encoding='utf-8')
|
||||
else:
|
||||
data = yaml.safe_load(filepath.read_text(encoding='utf-8'))
|
||||
return data.get('instruction_template', '')
|
||||
return ''
|
||||
templates = utils.get_available_instruction_templates() # ['None', ...]
|
||||
return [templates[0], 'Chat Template'] + templates[1:]
|
||||
|
||||
|
||||
def backup_adapter(input_folder):
|
||||
@@ -485,7 +466,8 @@ def do_train(lora_name: str, always_override: bool, all_linear: bool, q_proj_en:
|
||||
return
|
||||
else:
|
||||
# Load custom instruction template and set on tokenizer
|
||||
template_str = load_template(format)
|
||||
from modules.models_settings import load_template_by_name
|
||||
template_str = load_template_by_name(format)
|
||||
if not template_str:
|
||||
yield f"Error: could not load instruction template '{format}'."
|
||||
return
|
||||
|
||||
@@ -247,11 +247,16 @@ def get_available_users():
|
||||
return sorted(set((k.stem for k in paths)), key=natural_keys)
|
||||
|
||||
|
||||
YAML_EXTENSIONS = ('.yaml', '.yml')
|
||||
JINJA_EXTENSIONS = ('.jinja', '.jinja2')
|
||||
TEMPLATE_EXTENSIONS = JINJA_EXTENSIONS + YAML_EXTENSIONS
|
||||
|
||||
|
||||
def get_available_instruction_templates():
|
||||
path = str(shared.user_data_dir / "instruction-templates")
|
||||
path = shared.user_data_dir / "instruction-templates"
|
||||
paths = []
|
||||
if os.path.exists(path):
|
||||
paths = (x for x in Path(path).iterdir() if x.suffix in ('.json', '.yaml', '.yml'))
|
||||
if path.exists():
|
||||
paths = (x for x in path.iterdir() if x.suffix in TEMPLATE_EXTENSIONS)
|
||||
|
||||
return ['None'] + sorted(set((k.stem for k in paths)), key=natural_keys)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user