Skip to content

Commit 9e749f9

Browse files
authored
Merge pull request JamePeng#105 from TAO71-AI/lfm2.5-vl
Implement LFM2.5-VL Chat handler
2 parents ccc2af1 + 00e67b8 commit 9e749f9

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

llama_cpp/llama_chat_format.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5413,6 +5413,98 @@ def __call__(self, **kwargs):
54135413
# Use parent implementation
54145414
return super().__call__(**kwargs)
54155415

5416+
class LFM25VLChatHandler(MTMDChatHandler):
5417+
# Aligned with LFM2.5-VL tokenizer_config
5418+
LFM25VL_BOS_TOKEN = "<|startoftext|>"
5419+
LFM25VL_EOS_TOKEN = "<|im_end|>"
5420+
LFM25VL_PAD_TOKEN = "<|pad|>"
5421+
5422+
# Image specific tokens
5423+
LFM25VL_IMAGE_TOKEN = "<image>"
5424+
LFM25VL_IMAGE_START_TOKEN = "<|image_start|>"
5425+
LFM25VL_IMAGE_END_TOKEN = "<|image_end|>"
5426+
LFM25VL_IMAGE_THUMBNAIL = "<|img_thumbnail|>"
5427+
5428+
CHAT_FORMAT = (
5429+
"{{- bos_token -}}\n"
5430+
"{%- set keep_past_thinking = keep_past_thinking | default(false) -%}\n"
5431+
"{%- set ns = namespace(system_prompt='', content='') -%}\n"
5432+
"{%- if messages[0]['role'] == 'system' -%}\n"
5433+
" {%- set ns.system_prompt = messages[0]['content'] -%}\n"
5434+
" {%- set messages = messages[1:] -%}\n"
5435+
"{%- endif -%}\n"
5436+
"{%- if tools -%}\n"
5437+
" {%- set ns.system_prompt = ns.system_prompt + ('\\n' if ns.system_prompt else '') + 'List of tools: [' -%}\n"
5438+
" {%- for tool in tools -%}\n"
5439+
" {%- if tool is not string -%}\n"
5440+
" {%- set tool = tool | tojson -%}\n"
5441+
" {%- endif -%}\n"
5442+
" {%- set ns.system_prompt = ns.system_prompt + tool -%}\n"
5443+
" {%- if not loop.last -%}\n"
5444+
" {%- set ns.system_prompt = ns.system_prompt + ', ' -%}\n"
5445+
" {%- endif -%}\n"
5446+
" {%- endfor -%}\n"
5447+
" {%- set ns.system_prompt = ns.system_prompt + ']' -%}\n"
5448+
"{%- endif -%}\n"
5449+
"{%- if ns.system_prompt -%}\n"
5450+
" {{- '<|im_start|>system\\n' + ns.system_prompt + '<|im_end|>\\n' -}}\n"
5451+
"{%- endif -%}\n"
5452+
"{%- set ns.last_assistant_index = -1 -%}\n"
5453+
"{%- for message in messages -%}\n"
5454+
" {%- if message['role'] == 'assistant' -%}\n"
5455+
" {%- set ns.last_assistant_index = loop.index0 -%}\n"
5456+
" {%- endif -%}\n"
5457+
"{%- endfor -%}\n"
5458+
"{%- for message in messages -%}\n"
5459+
" {{- '<|im_start|>' + message['role'] + '\\n' -}}\n"
5460+
" {%- set content = message['content'] -%}\n"
5461+
" {%- if content is not string -%}\n"
5462+
" {%- set ns.content = '' -%}\n"
5463+
" {#- MTMD-style Multimodal Injection (Audio stripped for VL model) -#}\n"
5464+
" {%- for item in content -%}\n"
5465+
" {%- if item['type'] == 'image_url' -%}\n"
5466+
" {%- set img_val = item['image_url'] if item['image_url'] is string else item['image_url']['url'] -%}\n"
5467+
" {%- set ns.content = ns.content + img_val -%}\n"
5468+
" {%- elif item['type'] == 'text' -%}\n"
5469+
" {%- set ns.content = ns.content + item['text'] -%}\n"
5470+
" {%- else -%}\n"
5471+
" {%- set ns.content = ns.content + (item | tojson) -%}\n"
5472+
" {%- endif -%}\n"
5473+
" {%- endfor -%}\n"
5474+
" {%- set content = ns.content -%}\n"
5475+
" {%- endif -%}\n"
5476+
" {%- if message['role'] == 'assistant' and not keep_past_thinking and loop.index0 != ns.last_assistant_index -%}\n"
5477+
" {%- if '</think>' in content -%}\n"
5478+
" {%- set content = content.split('</think>')[-1] | trim -%}\n"
5479+
" {%- endif -%}\n"
5480+
" {%- endif -%}\n"
5481+
" {{- content + '<|im_end|>\\n' -}}\n"
5482+
"{%- endfor -%}\n"
5483+
"{%- if add_generation_prompt -%}\n"
5484+
" {{- '<|im_start|>assistant\\n' -}}\n"
5485+
"{%- endif -%}\n"
5486+
)
5487+
5488+
def __init__(self, keep_past_thinking: bool = False, **kwargs):
5489+
self.keep_past_thinking = keep_past_thinking
5490+
super().__init__(**kwargs)
5491+
5492+
5493+
def __call__(self, **kwargs):
5494+
if self.image_min_tokens > 256:
5495+
if self.verbose:
5496+
print(f"For LFM2.5-VL, using values higher than 256 for `image_min_tokens` could cause errors. Setting to **256**.")
5497+
5498+
self.image_min_tokens = 256
5499+
5500+
self.extra_template_arguments["keep_past_thinking"] = self.keep_past_thinking
5501+
5502+
kwargs['stop'] = [self.LFM25VL_EOS_TOKEN]
5503+
5504+
if self.verbose:
5505+
print(f"{self.log_prefix}(keep_past_thinking={self.keep_past_thinking}) - Start processing")
5506+
return super().__call__(**kwargs)
5507+
54165508
@register_chat_completion_handler("chatml-function-calling")
54175509
def chatml_function_calling(
54185510
llama: llama_core.Llama,

0 commit comments

Comments
 (0)