4using System.Collections.Generic;
24 public static Dictionary<string, ChatTemplate>
templates;
27 public static Dictionary<string, string> templatesDescription;
28 public static Dictionary<string, string> modelTemplates;
29 public static Dictionary<string, string> chatTemplates;
53 templates =
new Dictionary<string, ChatTemplate>();
54 templatesDescription =
new Dictionary<string, string>();
55 modelTemplates =
new Dictionary<string, string>();
56 chatTemplates =
new Dictionary<string, string>();
59 if (
templates.ContainsKey(
template.GetName()))
LLMUnitySetup.LogError($
"{template.GetName()} already in templates");
61 if (templatesDescription.ContainsKey(
template.GetDescription()))
LLMUnitySetup.LogError($
"{template.GetDescription()} already in templatesDescription");
62 templatesDescription[
template.GetDescription()] =
template.GetName();
65 if (modelTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"{match} already in modelTemplates");
66 modelTemplates[match] =
template.GetName();
70 if (chatTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"{match} already in chatTemplates");
71 chatTemplates[match] =
template.GetName();
84 if (name ==
null)
return null;
85 string nameLower = name.ToLower();
86 foreach (var pair
in modelTemplates)
88 if (nameLower.Contains(pair.Key))
return pair.Value;
100 if (
template ==
null)
return null;
101 string templateTrim =
template.Trim();
102 if (chatTemplates.TryGetValue(templateTrim, out
string value))
126 if (name !=
null)
return name;
129 if (name !=
null)
return name;
131 name =
FromName(Path.GetFileNameWithoutExtension(path));
132 if (name !=
null)
return name;
134 LLMUnitySetup.Log(
"No chat template could be matched, fallback to ChatML");
149 public virtual string GetName() {
return ""; }
157 public virtual string[]
GetStop(
string playerName,
string AIName) {
return new string[] {}; }
159 protected virtual string PromptPrefix() {
return ""; }
160 protected virtual string SystemPrefix() {
return ""; }
161 protected virtual string SystemSuffix() {
return ""; }
162 protected virtual string PlayerPrefix(
string playerName) {
return ""; }
163 protected virtual string AIPrefix(
string AIName) {
return ""; }
164 protected virtual string PrefixMessageSeparator() {
return ""; }
165 protected virtual string RequestPrefix() {
return ""; }
166 protected virtual string RequestSuffix() {
return ""; }
167 protected virtual string PairSuffix() {
return ""; }
174 public virtual string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
176 string chatPrompt = PromptPrefix();
178 if (messages[0].role ==
"system")
180 chatPrompt += RequestPrefix() + SystemPrefix() + messages[0].content + SystemSuffix();
183 for (
int i = start; i < messages.Count; i += 2)
185 if (i > start || start == 0) chatPrompt += RequestPrefix();
186 chatPrompt += PlayerPrefix(messages[i].role) + PrefixMessageSeparator() + messages[i].content + RequestSuffix();
187 if (i < messages.Count - 1)
189 chatPrompt += AIPrefix(messages[i + 1].role) + PrefixMessageSeparator() + messages[i + 1].content + PairSuffix();
192 if (endWithPrefix) chatPrompt += AIPrefix(AIName);
196 protected string[] AddStopNewlines(
string[] stop)
198 List<string> stopWithNewLines =
new List<string>();
199 foreach (
string stopword
in stop)
201 stopWithNewLines.Add(stopword);
202 stopWithNewLines.Add(
"\n" + stopword);
204 return stopWithNewLines.ToArray();
214 public override string GetName() {
return "chatml"; }
216 public override string[]
GetNameMatches() {
return new string[] {
"chatml",
"hermes",
"qwen"}; }
217 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 %}"}; }
219 protected override string SystemPrefix() {
return "<|im_start|>system\n"; }
220 protected override string SystemSuffix() {
return "<|im_end|>\n"; }
221 protected override string PlayerPrefix(
string playerName) {
return $
"<|im_start|>{playerName}\n"; }
222 protected override string AIPrefix(
string AIName) {
return $
"<|im_start|>{AIName}\n"; }
223 protected override string RequestSuffix() {
return "<|im_end|>\n"; }
224 protected override string PairSuffix() {
return "<|im_end|>\n"; }
226 public override string[]
GetStop(
string playerName,
string AIName)
228 return AddStopNewlines(
new string[] {
"<|im_start|>",
"<|im_end|>" });
238 public override string GetName() {
return "llama"; }
241 protected override string SystemPrefix() {
return "<<SYS>>\n"; }
242 protected override string SystemSuffix() {
return "\n<</SYS>> "; }
243 protected override string RequestPrefix() {
return "<s>[INST] "; }
244 protected override string RequestSuffix() {
return " [/INST]"; }
245 protected override string PairSuffix() {
return " </s>"; }
247 public override string[]
GetStop(
string playerName,
string AIName)
249 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]" });
259 public override string GetName() {
return "llama chat"; }
261 public override string[]
GetNameMatches() {
return new string[] {
"llama-2",
"llama v2"}; }
263 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
264 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
265 protected override string PrefixMessageSeparator() {
return " "; }
267 public override string[]
GetStop(
string playerName,
string AIName)
269 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]",
"###" });
279 public override string GetName() {
return "llama3 chat"; }
281 public override string[]
GetNameMatches() {
return new string[] {
"llama-3",
"llama v3"}; }
282 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' }}"};}
284 protected override string SystemPrefix() {
return "<|start_header_id|>system<|end_header_id|>\n\n"; }
285 protected override string SystemSuffix() {
return "<|eot_id|>"; }
287 protected override string RequestSuffix() {
return "<|eot_id|>"; }
288 protected override string PairSuffix() {
return "<|eot_id|>"; }
290 protected override string PlayerPrefix(
string playerName) {
return $
"<|start_header_id|>{playerName}<|end_header_id|>\n\n"; }
291 protected override string AIPrefix(
string AIName) {
return $
"<|start_header_id|>{AIName}<|end_header_id|>\n\n"; }
293 public override string[]
GetStop(
string playerName,
string AIName)
295 return AddStopNewlines(
new string[] {
"<|eot_id|>" });
305 public override string GetName() {
return "mistral instruct"; }
308 protected override string SystemPrefix() {
return ""; }
309 protected override string SystemSuffix() {
return "\n\n"; }
310 protected override string RequestPrefix() {
return "[INST] "; }
311 protected override string RequestSuffix() {
return " [/INST]"; }
312 protected override string PairSuffix() {
return "</s>"; }
314 public override string[]
GetStop(
string playerName,
string AIName)
316 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]" });
326 public override string GetName() {
return "mistral chat"; }
329 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 %}"}; }
331 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
332 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
333 protected override string PrefixMessageSeparator() {
return " "; }
335 public override string[]
GetStop(
string playerName,
string AIName)
337 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]",
"###" });
347 public override string GetName() {
return "gemma"; }
351 protected override string RequestSuffix() {
return "<end_of_turn>\n"; }
352 protected override string PairSuffix() {
return "<end_of_turn>\n"; }
354 protected override string PlayerPrefix(
string playerName) {
return "<start_of_turn>" + playerName +
"\n"; }
355 protected override string AIPrefix(
string AIName) {
return "<start_of_turn>" + AIName +
"\n"; }
357 public override string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
359 List<ChatMessage> messagesSystemPrompt = messages;
360 if (messages[0].role ==
"system")
362 string firstUserMessage = messages[0].content;
364 if (messages.Count > 1)
366 if (firstUserMessage !=
"") firstUserMessage +=
"\n\n";
367 firstUserMessage += messages[1].content;
370 messagesSystemPrompt =
new List<ChatMessage>(){
new ChatMessage { role = playerName, content = firstUserMessage }};
371 messagesSystemPrompt.AddRange(messages.GetRange(start, messages.Count - start));
373 return base.ComputePrompt(messagesSystemPrompt, playerName, AIName, endWithPrefix);
376 public override string[]
GetStop(
string playerName,
string AIName)
378 return AddStopNewlines(
new string[] {
"<start_of_turn>",
"<end_of_turn>" });
388 public override string GetName() {
return "alpaca"; }
392 protected override string SystemSuffix() {
return "\n\n"; }
393 protected override string RequestSuffix() {
return "\n"; }
394 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
395 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
396 protected override string PrefixMessageSeparator() {
return " "; }
397 protected override string PairSuffix() {
return "\n"; }
399 public override string[]
GetStop(
string playerName,
string AIName)
401 return AddStopNewlines(
new string[] {
"###" });
411 public override string GetName() {
return "vicuna"; }
414 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 %}"}; }
416 protected override string SystemSuffix() {
return "\n"; }
417 protected override string PlayerPrefix(
string playerName) {
return "\n" + playerName +
":"; }
418 protected override string AIPrefix(
string AIName) {
return "\n" + AIName +
":"; }
419 protected override string PrefixMessageSeparator() {
return " "; }
421 public override string[]
GetStop(
string playerName,
string AIName)
423 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
433 public override string GetName() {
return "phi"; }
437 protected override string SystemSuffix() {
return "\n\n"; }
438 protected override string RequestSuffix() {
return "\n"; }
439 protected override string PlayerPrefix(
string playerName) {
return playerName +
":"; }
440 protected override string AIPrefix(
string AIName) {
return AIName +
":"; }
441 protected override string PrefixMessageSeparator() {
return " "; }
442 protected override string PairSuffix() {
return "\n"; }
444 public override string[]
GetStop(
string playerName,
string AIName)
446 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
456 public override string GetName() {
return "phi-3"; }
459 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 %}"}; }
461 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
462 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
463 protected override string RequestSuffix() {
return "<|end|>\n"; }
464 protected override string PairSuffix() {
return "<|end|>\n"; }
467 public override string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
469 List<ChatMessage> messagesSystemPrompt = messages;
470 if (messages[0].role ==
"system")
472 string firstUserMessage = messages[0].content;
474 if (messages.Count > 1)
476 if (firstUserMessage !=
"") firstUserMessage +=
"\n\n";
477 firstUserMessage += messages[1].content;
480 messagesSystemPrompt =
new List<ChatMessage>(){
new ChatMessage { role =
"user", content = firstUserMessage }};
481 messagesSystemPrompt.AddRange(messages.GetRange(start, messages.Count - start));
483 return base.ComputePrompt(messagesSystemPrompt, playerName, AIName, endWithPrefix);
486 public override string[]
GetStop(
string playerName,
string AIName)
488 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
498 public override string GetName() {
return "phi-3.5"; }
501 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 %}"};}
503 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
504 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
505 protected override string RequestSuffix() {
return "<|end|>\n"; }
506 protected override string PairSuffix() {
return "<|end|>\n"; }
507 protected override string SystemPrefix() {
return "<|system|>\n"; }
508 protected override string SystemSuffix() {
return "<|end|>\n"; }
510 public override string[]
GetStop(
string playerName,
string AIName)
512 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
522 public override string GetName() {
return "zephyr"; }
525 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 %}"}; }
527 protected override string SystemPrefix() {
return "<|system|>\n"; }
528 protected override string SystemSuffix() {
return "</s>\n"; }
529 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
530 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
531 protected override string RequestSuffix() {
return "</s>\n"; }
532 protected override string PairSuffix() {
return "</s>\n"; }
534 public override string[]
GetStop(
string playerName,
string AIName)
536 return AddStopNewlines(
new string[] { $
"<|user|>", $
"<|assistant|>" });
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[] 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 ComputePrompt(List< ChatMessage > messages, string playerName, string AIName, bool endWithPrefix=true)
Constructs the prompt using the template based on a list of ChatMessages.
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 GGUF reader.
string GetStringField(string key)
Allows to retrieve a string GGUF field.
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 ComputePrompt(List< ChatMessage > messages, 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.
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.
override string ComputePrompt(List< ChatMessage > messages, string playerName, string AIName, bool endWithPrefix=true)
Constructs the prompt using the template based on a list of ChatMessages.
Class implementing the Phi-3.5 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 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.