Blame Raw
· · · 198 lines (6.7 KB)
0 contributors
1import { t } from './i18n.js';
2
3// the hash can be obtained from command line e.g. via: MODEL=path_to_model; python -c "import json, hashlib, sys; print(hashlib.sha256(json.load(open('"$MODEL"/tokenizer_config.json'))['chat_template'].encode()).hexdigest())"
4// note that chat templates must be trimmed to match the llama.cpp metadata value
5const hash_derivations = {
6 // Meta
7 'e10ca381b1ccc5cf9db52e371f3b6651576caee0a630b452e2816b2d404d4b65':
8 // Meta-Llama-3.1-8B-Instruct
9 // Meta-Llama-3.1-70B-Instruct
10 'Llama 3 Instruct'
11 ,
12 '5816fce10444e03c2e9ee1ef8a4a1ea61ae7e69e438613f3b17b69d0426223a4':
13 // Llama-3.2-1B-Instruct
14 // Llama-3.2-3B-Instruct
15 'Llama 3 Instruct'
16 ,
17 '73e87b1667d87ab7d7b579107f01151b29ce7f3ccdd1018fdc397e78be76219d':
18 // Nemotron 70B
19 'Llama 3 Instruct'
20 ,
21
22 // Mistral
23 // Mistral Reference: https://github.com/mistralai/mistral-common
24 'e16746b40344d6c5b5265988e0328a0bf7277be86f1c335156eae07e29c82826':
25 // Mistral-Small-Instruct-2409
26 // Mistral-Large-Instruct-2407
27 'Mistral V2 & V3'
28 ,
29 '26a59556925c987317ce5291811ba3b7f32ec4c647c400c6cc7e3a9993007ba7':
30 // Mistral-7B-Instruct-v0.3
31 'Mistral V2 & V3'
32 ,
33 'e4676cb56dffea7782fd3e2b577cfaf1e123537e6ef49b3ec7caa6c095c62272':
34 // Mistral-Nemo-Instruct-2407
35 'Mistral V3-Tekken'
36 ,
37 '3c4ad5fa60dd8c7ccdf82fa4225864c903e107728fcaf859fa6052cb80c92ee9':
38 // Mistral-Large-Instruct-2411
39 'Mistral V7'
40 ,
41 '3934d199bfe5b6fab5cba1b5f8ee475e8d5738ac315f21cb09545b4e665cc005':
42 // Mistral Small 24B
43 'Mistral V7'
44 ,
45
46 // Gemma
47 'ecd6ae513fe103f0eb62e8ab5bfa8d0fe45c1074fa398b089c93a7e70c15cfd6':
48 // gemma-2-9b-it
49 // gemma-2-27b-it
50 'Gemma 2'
51 ,
52 '87fa45af6cdc3d6a9e4dd34a0a6848eceaa73a35dcfe976bd2946a5822a38bf3':
53 // gemma-2-2b-it
54 'Gemma 2'
55 ,
56 '7de1c58e208eda46e9c7f86397df37ec49883aeece39fb961e0a6b24088dd3c4':
57 // gemma-3
58 'Gemma 2'
59 ,
60
61 // Cohere
62 '3b54f5c219ae1caa5c0bb2cdc7c001863ca6807cf888e4240e8739fa7eb9e02e':
63 // command-r-08-2024
64 'Command R'
65 ,
66
67 // Tulu
68 'ac7498a36a719da630e99d48e6ebc4409de85a77556c2b6159eeb735bcbd11df':
69 // Tulu-3-8B
70 // Tulu-3-70B
71 'Tulu'
72 ,
73
74 // DeepSeek V2.5
75 '54d400beedcd17f464e10063e0577f6f798fa896266a912d8a366f8a2fcc0bca':
76 'DeepSeek-V2.5'
77 ,
78
79 // DeepSeek R1
80 'b6835114b7303ddd78919a82e4d9f7d8c26ed0d7dfc36beeb12d524f6144eab1':
81 'DeepSeek-V2.5'
82 ,
83
84 // THUDM-GLM 4
85 '854b703e44ca06bdb196cc471c728d15dbab61e744fe6cdce980086b61646ed1':
86 'GLM-4'
87 ,
88
89 // Kimi K2, ...
90 'aab20feb9bc6881f941ea649356130ffbc4943b3c2577c0991e1fba90de5a0fc':
91 'Moonshot AI'
92 ,
93
94 // gpt-oss (unsloth)
95 '70da0d2348e40aaf8dad05f04a316835fd10547bd7e3392ce337e4c79ba91c01':
96 'OpenAI Harmony'
97 ,
98
99 // gpt-oss (ggml-org)
100 'a4c9919cbbd4acdd51ccffe22da049264b1b73e59055fa58811a99efbd7c8146':
101 'OpenAI Harmony'
102 ,
103};
104
105const substr_derivations = [
106 ['Moonshot AI', ['<|im_user|>user<|im_middle|>', '<|im_assistant|>assistant<|im_middle|>', '<|im_end|>']],
107 ['OpenAI Harmony', ['<|start|>user<|message|>', '<|start|>assistant<|channel|>final<|message|>', '<|end|>']],
108
109 // Generic cases
110 ['ChatML', ['<|im_start|>user', '<|im_start|>assistant', '<|im_end|>']],
111];
112
113const parse_derivation = derivation => (typeof derivation === 'string') ? {
114 'context': derivation,
115 'instruct': derivation,
116} : derivation;
117
118const not_found = { context: null, instruct: null };
119
120export async function deriveTemplatesFromChatTemplate(chat_template, hash) {
121 if (chat_template.trim() === '') {
122 console.log('Missing chat template.');
123 return not_found;
124 }
125
126 if (hash in hash_derivations) {
127 return parse_derivation(hash_derivations[hash]);
128 }
129
130 // heuristics
131 for (const [derivation, substr] of substr_derivations) {
132 if ([substr].flat().every(str => chat_template.includes(str))) {
133 return parse_derivation(derivation);
134 }
135 }
136
137 console.warn(`Unknown chat template hash: ${hash} for [${chat_template}]`);
138 return not_found;
139}
140
141export async function bindModelTemplates(power_user, online_status) {
142 if (online_status === 'no_connection') {
143 return false;
144 }
145
146 const chatTemplateHash = power_user.chat_template_hash;
147 const bindModelTemplates = power_user.model_templates_mappings[online_status]
148 ?? power_user.model_templates_mappings[chatTemplateHash]
149 ?? {};
150 const bindingsMatch = bindModelTemplates
151 && power_user.context.preset == bindModelTemplates.context
152 && (!power_user.instruct.enabled || power_user.instruct.preset === bindModelTemplates.instruct);
153
154 const bound = [];
155
156 if (bindingsMatch) {
157 // unmap current preset
158 delete power_user.model_templates_mappings[chatTemplateHash];
159 delete power_user.model_templates_mappings[online_status];
160 toastr.info(t`Context preset for ${online_status} will use defaults when loaded the next time.`);
161 } else {
162 if (power_user.context_derived) {
163 if (power_user.context.preset !== bindModelTemplates.context) {
164 bound.push(`${power_user.context.preset} context preset`);
165 // toastr.info(`Bound ${power_user.context.preset} preset to currently loaded model and all models that share its chat template.`);
166
167 // map current preset to current chat template hash
168 bindModelTemplates.context = power_user.context.preset;
169 }
170 } else {
171 toastr.warning(t`Note: Context derivation is disabled. Not including context preset.`);
172 }
173 if (power_user.instruct.enabled) {
174 if (power_user.instruct_derived) {
175 if (power_user.instruct.preset !== bindModelTemplates.instruct) {
176 bound.push(`${power_user.instruct.preset} instruct preset`);
177 bindModelTemplates.instruct = power_user.instruct.preset;
178 }
179 } else {
180 toastr.warning(t`Note: Instruct derivation is disabled. Not including instruct preset.`);
181 }
182 }
183 if (bound.length == 0) {
184 toastr.warning(t`No applicable presets available.`);
185 return false;
186 }
187
188 toastr.info(t`Bound ${online_status} to ${bound.join(', ')}.`);
189 if (!online_status.startsWith('koboldcpp/ggml-model-')) {
190 power_user.model_templates_mappings[online_status] = bindModelTemplates;
191 }
192 if (chatTemplateHash !== '') {
193 power_user.model_templates_mappings[chatTemplateHash] = bindModelTemplates;
194 }
195 }
196
197 return true;
198}