LLM for Unity  v2.5.0
Create characters in Unity with LLMs!
Loading...
Searching...
No Matches
LLMChatTemplates.cs
Go to the documentation of this file.
1
3using System.Collections.Generic;
4using System.Diagnostics;
5using System.IO;
6using System.Text;
7
8namespace LLMUnity
9{
14 public abstract class ChatTemplate
15 {
17 public static string DefaultTemplate;
24 public static Dictionary<string, ChatTemplate> templates;
26 public static ChatTemplate[] templateClasses;
27 public static Dictionary<string, string> templatesDescription;
28 public static Dictionary<string, string> modelTemplates;
29 public static Dictionary<string, string> chatTemplates;
31
32 static ChatTemplate()
33 {
34 DefaultTemplate = "chatml";
35
36 templateClasses = new ChatTemplate[]
37 {
38 new ChatMLTemplate(),
39 new AlpacaTemplate(),
40 new GemmaTemplate(),
45 new LLama2Template(),
46 new Phi4MiniTemplate(),
47 new Phi4Template(),
48 new Phi3_5Template(),
49 new Phi3Template(),
50 new Phi2Template(),
54 new VicunaTemplate(),
55 new ZephyrTemplate(),
56 };
57
58 templates = new Dictionary<string, ChatTemplate>();
59 templatesDescription = new Dictionary<string, string>();
60 modelTemplates = new Dictionary<string, string>();
61 chatTemplates = new Dictionary<string, string>();
62 foreach (ChatTemplate template in templateClasses)
63 {
64 if (templates.ContainsKey(template.GetName())) LLMUnitySetup.LogError($"{template.GetName()} already in templates");
65 templates[template.GetName()] = template;
66 if (templatesDescription.ContainsKey(template.GetDescription())) LLMUnitySetup.LogError($"{template.GetDescription()} already in templatesDescription");
67 templatesDescription[template.GetDescription()] = template.GetName();
68 foreach (string match in template.GetNameMatches())
69 {
70 if (modelTemplates.ContainsKey(match)) LLMUnitySetup.LogError($"Name for {template.GetName()} already in modelTemplates");
71 modelTemplates[match] = template.GetName();
72 }
73 foreach (string match in template.GetChatTemplateMatches())
74 {
75 if (chatTemplates.ContainsKey(match)) LLMUnitySetup.LogError($"Chat template for {template.GetName()} already in chatTemplates");
76 chatTemplates[match] = template.GetName();
77 }
78 }
79 }
80
87 public static string FromName(string name)
88 {
89 if (name == null) return null;
90 string nameLower = name.ToLower();
91 foreach (var pair in modelTemplates)
92 {
93 if (nameLower.Contains(pair.Key)) return pair.Value;
94 }
95 return null;
96 }
97
103 public static string FromTemplate(string template)
104 {
105 if (template == null) return null;
106 string templateTrim = template.Trim();
107 if (chatTemplates.TryGetValue(templateTrim, out string value))
108 return value;
109 return null;
110 }
111
122 public static string FromGGUF(string path)
123 {
124 return FromGGUF(new GGUFReader(path), path);
125 }
126
127 public static string FromGGUF(GGUFReader reader, string path)
128 {
129 string name;
130 name = FromTemplate(reader.GetStringField("tokenizer.chat_template"));
131 if (name != null) return name;
132
133 name = FromName(reader.GetStringField("general.name"));
134 if (name != null) return name;
135
136 name = FromName(Path.GetFileNameWithoutExtension(path));
137 if (name != null) return name;
138
139 LLMUnitySetup.Log("No chat template could be matched, fallback to ChatML");
140 return DefaultTemplate;
141 }
142
148 public static ChatTemplate GetTemplate(string template)
149 {
150 return templates[template];
151 }
152
154 public virtual string GetName() { return ""; }
156 public virtual string GetDescription() { return ""; }
158 public virtual string[] GetNameMatches() { return new string[] {}; }
160 public virtual string[] GetChatTemplateMatches() { return new string[] {}; }
162 public virtual string[] GetStop(string playerName, string AIName) { return new string[] {}; }
163
164 protected virtual string PromptPrefix() { return ""; }
165 protected virtual string SystemPrefix() { return ""; }
166 protected virtual string SystemSuffix() { return ""; }
167 protected virtual string PlayerPrefix(string playerName) { return ""; }
168 protected virtual string AIPrefix(string AIName) { return ""; }
169 protected virtual string PrefixMessageSeparator() { return ""; }
170 protected virtual string RequestPrefix() { return ""; }
171 protected virtual string RequestSuffix() { return ""; }
172 protected virtual string PairSuffix() { return ""; }
173
174 protected virtual bool SystemPromptSupported() { return true; }
175
181 public virtual string ComputePrompt(List<ChatMessage> chatMessages, string playerName, string AIName, bool endWithPrefix = true)
182 {
183 List<ChatMessage> messages = chatMessages;
184 if (!SystemPromptSupported())
185 {
186 if (chatMessages[0].role == "system")
187 {
188 string firstUserMessage = chatMessages[0].content;
189 int newStart = 1;
190 if (chatMessages.Count > 1)
191 {
192 if (firstUserMessage != "") firstUserMessage += "\n\n";
193 firstUserMessage += chatMessages[1].content;
194 newStart = 2;
195 }
196 messages = new List<ChatMessage>(){new ChatMessage { role = playerName, content = firstUserMessage }};
197 messages.AddRange(chatMessages.GetRange(newStart, chatMessages.Count - newStart));
198 }
199 }
200
201 string chatPrompt = PromptPrefix();
202 int start = 0;
203 if (messages[0].role == "system")
204 {
205 chatPrompt += RequestPrefix() + SystemPrefix() + messages[0].content + SystemSuffix();
206 start = 1;
207 }
208 for (int i = start; i < messages.Count; i += 2)
209 {
210 if (i > start || start == 0) chatPrompt += RequestPrefix();
211 chatPrompt += PlayerPrefix(messages[i].role) + PrefixMessageSeparator() + messages[i].content + RequestSuffix();
212 if (i < messages.Count - 1)
213 {
214 chatPrompt += AIPrefix(messages[i + 1].role) + PrefixMessageSeparator() + messages[i + 1].content + PairSuffix();
215 }
216 }
217 if (endWithPrefix) chatPrompt += AIPrefix(AIName);
218 return chatPrompt;
219 }
220
221 protected string[] AddStopNewlines(string[] stop)
222 {
223 List<string> stopWithNewLines = new List<string>();
224 foreach (string stopword in stop)
225 {
226 stopWithNewLines.Add(stopword);
227 stopWithNewLines.Add("\n" + stopword);
228 }
229 return stopWithNewLines.ToArray();
230 }
231 }
232
238 {
239 public override string GetName() { return "chatml"; }
240 public override string GetDescription() { return "chatml (most widely used)"; }
241 public override string[] GetNameMatches() { return new string[] {"chatml", "hermes", "qwen"}; }
242 public override string[] GetChatTemplateMatches() { return new string[] {"{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"}; }
243
244 protected override string SystemPrefix() { return "<|im_start|>system\n"; }
245 protected override string SystemSuffix() { return "<|im_end|>\n"; }
246 protected override string PlayerPrefix(string playerName) { return $"<|im_start|>{playerName}\n"; }
247 protected override string AIPrefix(string AIName) { return $"<|im_start|>{AIName}\n"; }
248 protected override string RequestSuffix() { return "<|im_end|>\n"; }
249 protected override string PairSuffix() { return "<|im_end|>\n"; }
250
251 public override string[] GetStop(string playerName, string AIName)
252 {
253 return AddStopNewlines(new string[] { "<|im_start|>", "<|im_end|>" });
254 }
255 }
256
262 {
263 public override string GetName() { return "llama"; }
264 public override string GetDescription() { return "llama 2"; }
265
266 protected override string SystemPrefix() { return "<<SYS>>\n"; }
267 protected override string SystemSuffix() { return "\n<</SYS>> "; }
268 protected override string RequestPrefix() { return "<s>[INST] "; }
269 protected override string RequestSuffix() { return " [/INST]"; }
270 protected override string PairSuffix() { return " </s>"; }
271
272 public override string[] GetStop(string playerName, string AIName)
273 {
274 return AddStopNewlines(new string[] { "[INST]", "[/INST]" });
275 }
276 }
277
283 {
284 public override string GetName() { return "llama chat"; }
285 public override string GetDescription() { return "llama 2 (chat)"; }
286 public override string[] GetNameMatches() { return new string[] {"llama-2", "llama v2"}; }
287
288 protected override string PlayerPrefix(string playerName) { return "### " + playerName + ":"; }
289 protected override string AIPrefix(string AIName) { return "### " + AIName + ":"; }
290 protected override string PrefixMessageSeparator() { return " "; }
291
292 public override string[] GetStop(string playerName, string AIName)
293 {
294 return AddStopNewlines(new string[] { "[INST]", "[/INST]", "###" });
295 }
296 }
297
303 {
304 public override string GetName() { return "llama3 chat"; }
305 public override string GetDescription() { return "llama 3 (chat)"; }
306 public override string[] GetNameMatches() { return new string[] {"llama-3", "llama v3"}; }
307 public override string[] GetChatTemplateMatches() { return new string[] {"{% set loop_messages = messages %}{% for message in loop_messages %}{% set content = '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n'+ message['content'] | trim + '<|eot_id|>' %}{% if loop.index0 == 0 %}{% set content = bos_token + content %}{% endif %}{{ content }}{% endfor %}{{ '<|start_header_id|>assistant<|end_header_id|>\n\n' }}"};}
308
309 protected override string SystemPrefix() { return "<|start_header_id|>system<|end_header_id|>\n\n"; }
310 protected override string SystemSuffix() { return "<|eot_id|>"; }
311
312 protected override string RequestSuffix() { return "<|eot_id|>"; }
313 protected override string PairSuffix() { return "<|eot_id|>"; }
314
315 protected override string PlayerPrefix(string playerName) { return $"<|start_header_id|>{playerName}<|end_header_id|>\n\n"; }
316 protected override string AIPrefix(string AIName) { return $"<|start_header_id|>{AIName}<|end_header_id|>\n\n"; }
317
318 public override string[] GetStop(string playerName, string AIName)
319 {
320 return AddStopNewlines(new string[] { "<|eot_id|>" });
321 }
322 }
323
329 {
330 public override string GetName() { return "mistral instruct"; }
331 public override string GetDescription() { return "mistral instruct"; }
332
333 protected override string SystemPrefix() { return ""; }
334 protected override string SystemSuffix() { return "\n\n"; }
335 protected override string RequestPrefix() { return "[INST] "; }
336 protected override string RequestSuffix() { return " [/INST]"; }
337 protected override string PairSuffix() { return "</s>"; }
338
339 public override string[] GetStop(string playerName, string AIName)
340 {
341 return AddStopNewlines(new string[] { "</s>", "[INST]", "[/INST]" });
342 }
343 }
344
350 {
351 public override string GetName() { return "mistral chat"; }
352 public override string GetDescription() { return "mistral (chat)"; }
353 public override string[] GetNameMatches() { return new string[] {"mistral"}; }
354 public override string[] GetChatTemplateMatches() { return new string[] {"{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}"}; }
355
356 protected override string PlayerPrefix(string playerName) { return "### " + playerName + ":"; }
357 protected override string AIPrefix(string AIName) { return "### " + AIName + ":"; }
358 protected override string PrefixMessageSeparator() { return " "; }
359
360 public override string[] GetStop(string playerName, string AIName)
361 {
362 return AddStopNewlines(new string[] { "</s>", "[INST]", "[/INST]", "###" });
363 }
364 }
365
371 {
372 public override string GetName() { return "gemma"; }
373 public override string GetDescription() { return "gemma"; }
374 public override string[] GetNameMatches() { return new string[] {"gemma"}; }
375 public override string[] GetChatTemplateMatches() { return new string[] {"{{ bos_token }}{% if messages[0]['role'] == 'system' %}{{ raise_exception('System role not supported') }}{% endif %}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if (message['role'] == 'assistant') %}{% set role = 'model' %}{% else %}{% set role = message['role'] %}{% endif %}{{ '<start_of_turn>' + role + '\n' + message['content'] | trim + '<end_of_turn>\n' }}{% endfor %}{% if add_generation_prompt %}{{'<start_of_turn>model\n'}}{% endif %}"}; }
376
377 protected override string RequestSuffix() { return "<end_of_turn>\n"; }
378 protected override string PairSuffix() { return "<end_of_turn>\n"; }
379
380 protected override string PlayerPrefix(string playerName) { return "<start_of_turn>user\n"; }
381 protected override string AIPrefix(string AIName) { return "<start_of_turn>model\n"; }
382
383 protected override bool SystemPromptSupported() { return false; }
384
385 public override string[] GetStop(string playerName, string AIName)
386 {
387 return AddStopNewlines(new string[] { "<start_of_turn>", "<end_of_turn>" });
388 }
389 }
390
396 {
397 public override string GetName() { return "alpaca"; }
398 public override string GetDescription() { return "alpaca (best alternative)"; }
399 public override string[] GetNameMatches() { return new string[] {"alpaca"}; }
400
401 protected override string SystemSuffix() { return "\n\n"; }
402 protected override string RequestSuffix() { return "\n"; }
403 protected override string PlayerPrefix(string playerName) { return "### " + playerName + ":"; }
404 protected override string AIPrefix(string AIName) { return "### " + AIName + ":"; }
405 protected override string PrefixMessageSeparator() { return " "; }
406 protected override string PairSuffix() { return "\n"; }
407
408 public override string[] GetStop(string playerName, string AIName)
409 {
410 return AddStopNewlines(new string[] { "###" });
411 }
412 }
413
419 {
420 public override string GetName() { return "vicuna"; }
421 public override string GetDescription() { return "vicuna"; }
422 public override string[] GetNameMatches() { return new string[] {"vicuna"}; }
423 public override string[] GetChatTemplateMatches() { return new string[] {"{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{% if message['role'] == 'system' %}{{message['content'] + ' '}}{% elif message['role'] == 'user' %}{{ 'USER: ' + message['content'] + ' '}}{% elif message['role'] == 'assistant' %}{{ 'ASSISTANT: ' + message['content'] + ' '}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'ASSISTANT: '}}{% endif %}"}; }
424
425 protected override string SystemSuffix() { return "\n"; }
426 protected override string PlayerPrefix(string playerName) { return "\n" + playerName + ":"; }
427 protected override string AIPrefix(string AIName) { return "\n" + AIName + ":"; }
428 protected override string PrefixMessageSeparator() { return " "; }
429
430 public override string[] GetStop(string playerName, string AIName)
431 {
432 return AddStopNewlines(new string[] { playerName + ":", AIName + ":" });
433 }
434 }
435
441 {
442 public override string GetName() { return "phi"; }
443 public override string GetDescription() { return "phi-2"; }
444 public override string[] GetNameMatches() { return new string[] {"phi-2"}; }
445
446 protected override string SystemSuffix() { return "\n\n"; }
447 protected override string RequestSuffix() { return "\n"; }
448 protected override string PlayerPrefix(string playerName) { return playerName + ":"; }
449 protected override string AIPrefix(string AIName) { return AIName + ":"; }
450 protected override string PrefixMessageSeparator() { return " "; }
451 protected override string PairSuffix() { return "\n"; }
452
453 public override string[] GetStop(string playerName, string AIName)
454 {
455 return AddStopNewlines(new string[] { playerName + ":", AIName + ":" });
456 }
457 }
458
464 {
465 public override string GetName() { return "phi-3"; }
466 public override string GetDescription() { return "phi-3"; }
467 public override string[] GetNameMatches() { return new string[] {"phi-3"}; }
468 public override string[] GetChatTemplateMatches() { return new string[] {"{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') %}{{'<|user|>' + '\n' + message['content'] + '<|end|>' + '\n' + '<|assistant|>' + '\n'}}{% elif (message['role'] == 'assistant') %}{{message['content'] + '<|end|>' + '\n'}}{% endif %}{% endfor %}"}; }
469
470 protected override string PlayerPrefix(string playerName) { return $"<|user|>\n"; }
471 protected override string AIPrefix(string AIName) { return $"<|assistant|>\n"; }
472 protected override string RequestSuffix() { return "<|end|>\n"; }
473 protected override string PairSuffix() { return "<|end|>\n"; }
474
475 protected override bool SystemPromptSupported() { return false; }
476
477 public override string[] GetStop(string playerName, string AIName)
478 {
479 return AddStopNewlines(new string[] { "<|end|>", "<|user|>", "<|assistant|>" });
480 }
481 }
482
488 {
489 public override string GetName() { return "phi-3.5"; }
490 public override string GetDescription() { return "phi-3.5"; }
491 public override string[] GetNameMatches() { return new string[] {"phi-3.5"}; }
492 public override string[] GetChatTemplateMatches() { return new string[] {"{% for message in messages %}{% if message['role'] == 'system' and message['content'] %}{{'<|system|>\n' + message['content'] + '<|end|>\n'}}{% elif message['role'] == 'user' %}{{'<|user|>\n' + message['content'] + '<|end|>\n'}}{% elif message['role'] == 'assistant' %}{{'<|assistant|>\n' + message['content'] + '<|end|>\n'}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|assistant|>\n' }}{% else %}{{ eos_token }}{% endif %}"};}
493
494 protected override string PlayerPrefix(string playerName) { return $"<|user|>\n"; }
495 protected override string AIPrefix(string AIName) { return $"<|assistant|>\n"; }
496 protected override string RequestSuffix() { return "<|end|>\n"; }
497 protected override string PairSuffix() { return "<|end|>\n"; }
498 protected override string SystemPrefix() { return "<|system|>\n"; }
499 protected override string SystemSuffix() { return "<|end|>\n"; }
500
501 public override string[] GetStop(string playerName, string AIName)
502 {
503 return AddStopNewlines(new string[] { "<|end|>", "<|user|>", "<|assistant|>" });
504 }
505 }
506
512 {
513 public override string GetName() { return "phi-4-mini"; }
514 public override string GetDescription() { return "phi-4-mini"; }
515 public override string[] GetNameMatches() { return new string[] {"phi-4-mini"}; }
516 public override string[] GetChatTemplateMatches() { return new string[] {"{% for message in messages %}{% if message['role'] == 'system' and 'tools' in message and message['tools'] is not none %}{{ '<|' + message['role'] + '|>' + message['content'] + '<|tool|>' + message['tools'] + '<|/tool|>' + '<|end|>' }}{% else %}{{ '<|' + message['role'] + '|>' + message['content'] + '<|end|>' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|assistant|>' }}{% else %}{{ eos_token }}{% endif %}"};}
517
518 protected override string PlayerPrefix(string playerName) { return $"<|user|>"; }
519 protected override string AIPrefix(string AIName) { return $"<|assistant|>"; }
520 protected override string RequestSuffix() { return "<|end|>"; }
521 protected override string PairSuffix() { return "<|end|>"; }
522 protected override string SystemPrefix() { return "<|system|>"; }
523 protected override string SystemSuffix() { return "<|end|>"; }
524
525 public override string[] GetStop(string playerName, string AIName)
526 {
527 return AddStopNewlines(new string[] { "<|end|>", "<|user|>", "<|assistant|>" });
528 }
529 }
535 {
536 public override string GetName() { return "phi-4"; }
537 public override string GetDescription() { return "phi-4"; }
538 public override string[] GetNameMatches() { return new string[] {"phi-4"}; }
539 public override string[] GetChatTemplateMatches() { return new string[] {"{% for message in messages %}{% if (message['role'] == 'system') %}{{'<|im_start|>system<|im_sep|>' + message['content'] + '<|im_end|>'}}{% elif (message['role'] == 'user') %}{{'<|im_start|>user<|im_sep|>' + message['content'] + '<|im_end|>'}}{% elif (message['role'] == 'assistant') %}{{'<|im_start|>assistant<|im_sep|>' + message['content'] + '<|im_end|>'}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant<|im_sep|>' }}{% endif %}"};}
540
541 protected override string PlayerPrefix(string playerName) { return $"<|im_start|>user<|im_sep|>"; }
542 protected override string AIPrefix(string AIName) { return $"<|im_start|>assistant<|im_sep|>"; }
543 protected override string RequestSuffix() { return "<|im_end|>"; }
544 protected override string PairSuffix() { return "<|im_end|>"; }
545 protected override string SystemPrefix() { return "<|im_start|>system<|im_sep|>"; }
546 protected override string SystemSuffix() { return "<|im_end|>"; }
547
548 public override string[] GetStop(string playerName, string AIName)
549 {
550 return AddStopNewlines(new string[] { "<|im_end|>", "<|im_start|>" });
551 }
552 }
553
559 {
560 public override string GetName() { return "zephyr"; }
561 public override string GetDescription() { return "zephyr"; }
562 public override string[] GetNameMatches() { return new string[] {"zephyr"}; }
563 public override string[] GetChatTemplateMatches() { return new string[] {"{% for message in messages %}\n{% if message['role'] == 'user' %}\n{{ '<|user|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'system' %}\n{{ '<|system|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'assistant' %}\n{{ '<|assistant|>\n' + message['content'] + eos_token }}\n{% endif %}\n{% if loop.last and add_generation_prompt %}\n{{ '<|assistant|>' }}\n{% endif %}\n{% endfor %}"}; }
564
565 protected override string SystemPrefix() { return "<|system|>\n"; }
566 protected override string SystemSuffix() { return "</s>\n"; }
567 protected override string PlayerPrefix(string playerName) { return $"<|user|>\n"; }
568 protected override string AIPrefix(string AIName) { return $"<|assistant|>\n"; }
569 protected override string RequestSuffix() { return "</s>\n"; }
570 protected override string PairSuffix() { return "</s>\n"; }
571
572 public override string[] GetStop(string playerName, string AIName)
573 {
574 return AddStopNewlines(new string[] { $"<|user|>", $"<|assistant|>" });
575 }
576 }
577
583 {
584 public override string GetName() { return "deepseek-v2"; }
585 public override string GetDescription() { return "deepseek-v2"; }
586 public override string[] GetNameMatches() { return new string[] {"deepseek-v2", "deepseek-llm"}; }
587 public override string[] GetChatTemplateMatches() { return new string[] {"{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{{ bos_token }}{% for message in messages %}{% if message['role'] == 'user' %}{{ 'User: ' + message['content'] + '\n\n' }}{% elif message['role'] == 'assistant' %}{{ 'Assistant: ' + message['content'] + eos_token }}{% elif message['role'] == 'system' %}{{ message['content'] + '\n\n' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'Assistant:' }}{% endif %}"}; }
588
589 protected override string PrefixMessageSeparator() { return " "; }
590 protected override string PromptPrefix() { return "<|begin▁of▁sentence|>"; }
591 protected override string PlayerPrefix(string playerName) { return "User:"; }
592 protected override string AIPrefix(string AIName) { return "Assistant:"; }
593 protected override string PairSuffix() { return "<|end▁of▁sentence|>"; }
594 protected override string RequestSuffix() { return "\n\n"; }
595 protected override string SystemSuffix() { return "\n\n"; }
596
597 // protected override bool SystemPromptSupported() { return false; }
598
599 public override string[] GetStop(string playerName, string AIName)
600 {
601 return AddStopNewlines(new string[] { "<|end▁of▁sentence|>", "User:", "Assistant:" });
602 }
603 }
604
610 {
611 public override string GetName() { return "deepseek-v3"; }
612 public override string GetDescription() { return "deepseek-v3"; }
613 public override string[] GetNameMatches() { return new string[] {"deepseek-v2.5", "deepseek-v3"}; }
614 public override string[] GetChatTemplateMatches()
615 {
616 return new string[]
617 {
618 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{{'<|Assistant|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %}",
619 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='', is_first_sp=true) %}{%- for message in messages %}{%- if message['role'] == 'system' %}{%- if ns.is_first_sp %}{% set ns.system_prompt = ns.system_prompt + message['content'] %}{% set ns.is_first_sp = false %}{%- else %}{% set ns.system_prompt = ns.system_prompt + '\n\n' + message['content'] %}{%- endif %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{{'<|Assistant|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %}"
620 };
621 }
622
623 protected override string PrefixMessageSeparator() { return ""; }
624 protected override string PlayerPrefix(string playerName) { return "<|User|>"; }
625 protected override string AIPrefix(string AIName) { return "<|Assistant|>"; }
626 protected override string RequestSuffix() { return ""; }
627
628 public override string[] GetStop(string playerName, string AIName)
629 {
630 return AddStopNewlines(new string[] { "<|end▁of▁sentence|>", "<|User|>", "<|Assistant|>" });
631 }
632 }
633
639 {
640 public override string GetName() { return "deepseek-r1"; }
641 public override string GetDescription() { return "deepseek-r1"; }
642 public override string[] GetNameMatches() { return new string[] {"deepseek-r1"}; }
643 public override string[] GetChatTemplateMatches()
644 {
645 return new string[]
646 {
647 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='', is_first_sp=true) %}{%- for message in messages %}{%- if message['role'] == 'system' %}{%- if ns.is_first_sp %}{% set ns.system_prompt = ns.system_prompt + message['content'] %}{% set ns.is_first_sp = false %}{%- else %}{% set ns.system_prompt = ns.system_prompt + '\\n\\n' + message['content'] %}{%- endif %}{%- endif %}{%- endfor %}{{ bos_token }}{{ ns.system_prompt }}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and 'tool_calls' in message %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls'] %}{%- if not ns.is_first %}{%- if message['content'] is none %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- else %}{{'<|Assistant|>' + message['content'] + '<|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- endif %}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- endif %}{%- endfor %}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- if message['role'] == 'assistant' and 'tool_calls' not in message %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|><think>\\n'}}{% endif %}",
648 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|><think>\\n'}}{% endif %}"
649 };
650 }
651
652 public override string ComputePrompt(List<ChatMessage> chatMessages, string playerName, string AIName, bool endWithPrefix = true)
653 {
654 string prompt = base.ComputePrompt(chatMessages, playerName, AIName, endWithPrefix);
655 if (endWithPrefix) prompt += "<think>\n\n</think>\n\n";
656 return prompt;
657 }
658
659 public override string[] GetStop(string playerName, string AIName)
660 {
661 return AddStopNewlines(new string[] { "<|end▁of▁sentence|>", "<|User|>", "<|Assistant|>", "</think>" });
662 }
663 }
664}
Class implementing the Alpaca template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
Class implementing the ChatML template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the skeleton of a chat template.
static string FromGGUF(string path)
Determines the chat template name from a GGUF file. It reads the GGUF file and then determines the ch...
virtual string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
static Dictionary< string, ChatTemplate > templates
a dictionary from chat template name to chat template type. It can be used to get the chat template n...
virtual string ComputePrompt(List< ChatMessage > chatMessages, string playerName, string AIName, bool endWithPrefix=true)
Constructs the prompt using the template based on a list of ChatMessages.
virtual string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
static string FromName(string name)
Determines the chat template name from a search name. It searches if any of the chat template names i...
virtual string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
static ChatTemplate GetTemplate(string template)
Creates the chat template based on the provided chat template name.
virtual string GetName()
Returns the chat template name.
virtual string GetDescription()
Returns the chat template description.
static string FromTemplate(string template)
Determines the chat template name from a Jinja template.
static string DefaultTemplate
the default template used when it can't be determined ("chatml")
Class implementing the DeepSeek R1 template.
override string ComputePrompt(List< ChatMessage > chatMessages, string playerName, string AIName, bool endWithPrefix=true)
Constructs the prompt using the template based on a list of ChatMessages.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing the DeepSeek V2 template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
Class implementing the DeepSeek V3 template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the GGUF reader.
Definition LLMGGUF.cs:55
string GetStringField(string key)
Allows to retrieve a string GGUF field.
Definition LLMGGUF.cs:145
Class implementing the Gemma template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing helper functions for setup and process management.
Class implementing a modified version of the LLama2 template for chat.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
Class implementing the LLama2 template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the LLama3 template for chat.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing a modified version of the Mistral Instruct template for chat.
override string GetDescription()
Returns the chat template description.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Mistral Instruct template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Phi-2 template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
Class implementing the Phi-3 template.
override string GetDescription()
Returns the chat template description.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing the Phi-4 mini template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
Class implementing the Phi-4 mini template.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Phi-4 template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
Class implementing the Vicuna template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Zephyr template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.