3using System.Collections.Generic;
22 public static Dictionary<string, ChatTemplate>
templates;
25 public static Dictionary<string, string> templatesDescription;
26 public static Dictionary<string, string> modelTemplates;
27 public static Dictionary<string, string> chatTemplates;
51 templates =
new Dictionary<string, ChatTemplate>();
52 templatesDescription =
new Dictionary<string, string>();
53 modelTemplates =
new Dictionary<string, string>();
54 chatTemplates =
new Dictionary<string, string>();
57 if (
templates.ContainsKey(
template.GetName()))
LLMUnitySetup.LogError($
"{template.GetName()} already in templates");
59 if (templatesDescription.ContainsKey(
template.GetDescription()))
LLMUnitySetup.LogError($
"{template.GetDescription()} already in templatesDescription");
60 templatesDescription[
template.GetDescription()] =
template.GetName();
63 if (modelTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"{match} already in modelTemplates");
64 modelTemplates[match] =
template.GetName();
68 if (chatTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"{match} already in chatTemplates");
69 chatTemplates[match] =
template.GetName();
82 if (name ==
null)
return null;
83 string nameLower = name.ToLower();
84 foreach (var pair
in modelTemplates)
86 if (nameLower.Contains(pair.Key))
return pair.Value;
98 if (
template ==
null)
return null;
99 string templateTrim =
template.Trim();
100 if (chatTemplates.TryGetValue(templateTrim, out
string value))
124 if (name !=
null)
return name;
127 if (name !=
null)
return name;
129 name =
FromName(Path.GetFileNameWithoutExtension(path));
130 if (name !=
null)
return name;
132 LLMUnitySetup.Log(
"No chat template could be matched, fallback to ChatML");
147 public virtual string GetName() {
return ""; }
155 public virtual string[]
GetStop(
string playerName,
string AIName) {
return new string[] {}; }
157 protected virtual string PromptPrefix() {
return ""; }
158 protected virtual string SystemPrefix() {
return ""; }
159 protected virtual string SystemSuffix() {
return ""; }
160 protected virtual string PlayerPrefix(
string playerName) {
return ""; }
161 protected virtual string AIPrefix(
string AIName) {
return ""; }
162 protected virtual string PrefixMessageSeparator() {
return ""; }
163 protected virtual string RequestPrefix() {
return ""; }
164 protected virtual string RequestSuffix() {
return ""; }
165 protected virtual string PairSuffix() {
return ""; }
172 public virtual string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
174 string chatPrompt = PromptPrefix();
176 if (messages[0].role ==
"system")
178 chatPrompt += RequestPrefix() + SystemPrefix() + messages[0].content + SystemSuffix();
181 for (
int i = start; i < messages.Count; i += 2)
183 if (i > start || start == 0) chatPrompt += RequestPrefix();
184 chatPrompt += PlayerPrefix(messages[i].role) + PrefixMessageSeparator() + messages[i].content + RequestSuffix();
185 if (i < messages.Count - 1)
187 chatPrompt += AIPrefix(messages[i + 1].role) + PrefixMessageSeparator() + messages[i + 1].content + PairSuffix();
190 if (endWithPrefix) chatPrompt += AIPrefix(AIName);
194 protected string[] AddStopNewlines(
string[] stop)
196 List<string> stopWithNewLines =
new List<string>();
197 foreach (
string stopword
in stop)
199 stopWithNewLines.Add(stopword);
200 stopWithNewLines.Add(
"\n" + stopword);
202 return stopWithNewLines.ToArray();
212 public override string GetName() {
return "chatml"; }
214 public override string[]
GetNameMatches() {
return new string[] {
"chatml",
"hermes",
"qwen"}; }
215 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 %}"}; }
217 protected override string SystemPrefix() {
return "<|im_start|>system\n"; }
218 protected override string SystemSuffix() {
return "<|im_end|>\n"; }
219 protected override string PlayerPrefix(
string playerName) {
return $
"<|im_start|>{playerName}\n"; }
220 protected override string AIPrefix(
string AIName) {
return $
"<|im_start|>{AIName}\n"; }
221 protected override string RequestSuffix() {
return "<|im_end|>\n"; }
222 protected override string PairSuffix() {
return "<|im_end|>\n"; }
224 public override string[]
GetStop(
string playerName,
string AIName)
226 return AddStopNewlines(
new string[] {
"<|im_start|>",
"<|im_end|>" });
236 public override string GetName() {
return "llama"; }
239 protected override string SystemPrefix() {
return "<<SYS>>\n"; }
240 protected override string SystemSuffix() {
return "\n<</SYS>> "; }
241 protected override string RequestPrefix() {
return "<s>[INST] "; }
242 protected override string RequestSuffix() {
return " [/INST]"; }
243 protected override string PairSuffix() {
return " </s>"; }
245 public override string[]
GetStop(
string playerName,
string AIName)
247 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]" });
257 public override string GetName() {
return "llama chat"; }
259 public override string[]
GetNameMatches() {
return new string[] {
"llama-2",
"llama v2"}; }
261 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
262 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
263 protected override string PrefixMessageSeparator() {
return " "; }
265 public override string[]
GetStop(
string playerName,
string AIName)
267 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]",
"###" });
277 public override string GetName() {
return "llama3 chat"; }
279 public override string[]
GetNameMatches() {
return new string[] {
"llama-3",
"llama v3"}; }
280 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' }}"};}
282 protected override string SystemPrefix() {
return "<|start_header_id|>system<|end_header_id|>\n\n"; }
283 protected override string SystemSuffix() {
return "<|eot_id|>"; }
285 protected override string RequestSuffix() {
return "<|eot_id|>"; }
286 protected override string PairSuffix() {
return "<|eot_id|>"; }
288 protected override string PlayerPrefix(
string playerName) {
return $
"<|start_header_id|>{playerName}<|end_header_id|>\n\n"; }
289 protected override string AIPrefix(
string AIName) {
return $
"<|start_header_id|>{AIName}<|end_header_id|>\n\n"; }
291 public override string[]
GetStop(
string playerName,
string AIName)
293 return AddStopNewlines(
new string[] {
"<|eot_id|>" });
303 public override string GetName() {
return "mistral instruct"; }
306 protected override string SystemPrefix() {
return ""; }
307 protected override string SystemSuffix() {
return "\n\n"; }
308 protected override string RequestPrefix() {
return "[INST] "; }
309 protected override string RequestSuffix() {
return " [/INST]"; }
310 protected override string PairSuffix() {
return "</s>"; }
312 public override string[]
GetStop(
string playerName,
string AIName)
314 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]" });
324 public override string GetName() {
return "mistral chat"; }
327 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 %}"}; }
329 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
330 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
331 protected override string PrefixMessageSeparator() {
return " "; }
333 public override string[]
GetStop(
string playerName,
string AIName)
335 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]",
"###" });
345 public override string GetName() {
return "gemma"; }
349 protected override string RequestSuffix() {
return "<end_of_turn>\n"; }
350 protected override string PairSuffix() {
return "<end_of_turn>\n"; }
352 protected override string PlayerPrefix(
string playerName) {
return "<start_of_turn>" + playerName +
"\n"; }
353 protected override string AIPrefix(
string AIName) {
return "<start_of_turn>" + AIName +
"\n"; }
355 public override string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
357 List<ChatMessage> messagesSystemPrompt = messages;
358 if (messages[0].role ==
"system")
360 string firstUserMessage = messages[0].content;
362 if (messages.Count > 1)
364 if (firstUserMessage !=
"") firstUserMessage +=
"\n\n";
365 firstUserMessage += messages[1].content;
368 messagesSystemPrompt =
new List<ChatMessage>(){
new ChatMessage { role = playerName, content = firstUserMessage }};
369 messagesSystemPrompt.AddRange(messages.GetRange(start, messages.Count - start));
371 return base.ComputePrompt(messagesSystemPrompt, playerName, AIName, endWithPrefix);
374 public override string[]
GetStop(
string playerName,
string AIName)
376 return AddStopNewlines(
new string[] {
"<start_of_turn>",
"<end_of_turn>" });
386 public override string GetName() {
return "alpaca"; }
390 protected override string SystemSuffix() {
return "\n\n"; }
391 protected override string RequestSuffix() {
return "\n"; }
392 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
393 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
394 protected override string PrefixMessageSeparator() {
return " "; }
395 protected override string PairSuffix() {
return "\n"; }
397 public override string[]
GetStop(
string playerName,
string AIName)
399 return AddStopNewlines(
new string[] {
"###" });
409 public override string GetName() {
return "vicuna"; }
412 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 %}"}; }
414 protected override string SystemSuffix() {
return "\n"; }
415 protected override string PlayerPrefix(
string playerName) {
return "\n" + playerName +
":"; }
416 protected override string AIPrefix(
string AIName) {
return "\n" + AIName +
":"; }
417 protected override string PrefixMessageSeparator() {
return " "; }
419 public override string[]
GetStop(
string playerName,
string AIName)
421 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
431 public override string GetName() {
return "phi"; }
435 protected override string SystemSuffix() {
return "\n\n"; }
436 protected override string RequestSuffix() {
return "\n"; }
437 protected override string PlayerPrefix(
string playerName) {
return playerName +
":"; }
438 protected override string AIPrefix(
string AIName) {
return AIName +
":"; }
439 protected override string PrefixMessageSeparator() {
return " "; }
440 protected override string PairSuffix() {
return "\n"; }
442 public override string[]
GetStop(
string playerName,
string AIName)
444 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
454 public override string GetName() {
return "phi-3"; }
457 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 %}"}; }
459 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
460 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
461 protected override string RequestSuffix() {
return "<|end|>\n"; }
462 protected override string PairSuffix() {
return "<|end|>\n"; }
465 public override string ComputePrompt(List<ChatMessage> messages,
string playerName,
string AIName,
bool endWithPrefix =
true)
467 List<ChatMessage> messagesSystemPrompt = messages;
468 if (messages[0].role ==
"system")
470 string firstUserMessage = messages[0].content;
472 if (messages.Count > 1)
474 if (firstUserMessage !=
"") firstUserMessage +=
"\n\n";
475 firstUserMessage += messages[1].content;
478 messagesSystemPrompt =
new List<ChatMessage>(){
new ChatMessage { role =
"user", content = firstUserMessage }};
479 messagesSystemPrompt.AddRange(messages.GetRange(start, messages.Count - start));
481 return base.ComputePrompt(messagesSystemPrompt, playerName, AIName, endWithPrefix);
484 public override string[]
GetStop(
string playerName,
string AIName)
486 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
496 public override string GetName() {
return "phi-3.5"; }
499 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 %}"};}
501 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
502 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
503 protected override string RequestSuffix() {
return "<|end|>\n"; }
504 protected override string PairSuffix() {
return "<|end|>\n"; }
505 protected override string SystemPrefix() {
return "<|system|>\n"; }
506 protected override string SystemSuffix() {
return "<|end|>\n"; }
508 public override string[]
GetStop(
string playerName,
string AIName)
510 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
520 public override string GetName() {
return "zephyr"; }
523 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 %}"}; }
525 protected override string SystemPrefix() {
return "<|system|>\n"; }
526 protected override string SystemSuffix() {
return "</s>\n"; }
527 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
528 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
529 protected override string RequestSuffix() {
return "</s>\n"; }
530 protected override string PairSuffix() {
return "</s>\n"; }
532 public override string[]
GetStop(
string playerName,
string AIName)
534 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.