Skip to content

Commit ad174ba

Browse files
committed
Add fim template to instruct modal
1 parent 3526dfe commit ad174ba

File tree

1 file changed

+125
-39
lines changed

1 file changed

+125
-39
lines changed

mikupad.html

+125-39
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@
595595
.instructmodal-edits .hbox {
596596
margin-top:8px;
597597
}
598+
.instructmodal-edits .vbox {
599+
margin-top:8px;
600+
}
598601

599602

600603

@@ -2669,6 +2672,7 @@
26692672
"sysSuf": "",
26702673
"instPre": "",
26712674
"instSuf": "",
2675+
"fimTemplate": undefined,
26722676
}
26732677
return { ...newState }
26742678
})
@@ -2748,6 +2752,7 @@
27482752
"sysSuf": template.affixes.sysSuf,
27492753
"instPre": template.affixes.instPre,
27502754
"instSuf": template.affixes.instSuf,
2755+
"fimTemplate": template.affixes.fimTemplate,
27512756
}
27522757
}
27532758
return { ...newState }
@@ -2888,7 +2893,7 @@
28882893
onInput=${e => handleInstructTemplateChange(selectedTemplate,"instPre",e.target.value)}
28892894
onValueChange=${() => {}}/>
28902895
2891-
<${InputBox} label="Instruct Suffix {/inst}"
2896+
<${InputBox} label="Instruct Suffix {/inst}"
28922897
placeholder="[/INST]"
28932898
className=""
28942899
tooltip=""
@@ -2908,7 +2913,7 @@
29082913
onInput=${e => handleInstructTemplateChange(selectedTemplate,"sysPre",e.target.value)}
29092914
onValueChange=${() => {}}/>
29102915
2911-
<${InputBox} label="System Prompt Suffix {/sys}"
2916+
<${InputBox} label="System Prompt Suffix {/sys}"
29122917
placeholder="<</SYS>>\n\n"
29132918
className=""
29142919
tooltip=""
@@ -2917,6 +2922,32 @@
29172922
onInput=${e => handleInstructTemplateChange(selectedTemplate,"sysSuf",e.target.value)}
29182923
onValueChange=${() => {}}/>
29192924
</div>
2925+
2926+
<div className="hbox">
2927+
<div className="vbox">
2928+
<${Checkbox} label="Supports Fill-In-The-Middle"
2929+
value=${getArrObjByName(templateList,selectedTemplate)?.affixes.fimTemplate !== undefined}
2930+
onValueChange=${(value) => handleInstructTemplateChange(selectedTemplate,"fimTemplate", value ? '' : undefined)}/>
2931+
${getArrObjByName(templateList,selectedTemplate)?.affixes.fimTemplate !== undefined && html`
2932+
<${InputBox} label="Fill-In-The-Middle Template"
2933+
placeholder="[SUFFIX]{suffix}[PREFIX]{prefix}"
2934+
className=""
2935+
tooltip=""
2936+
readOnly=${!!cancel}
2937+
value=${getArrObjByName(templateList,selectedTemplate)?.affixes.fimTemplate || ""}
2938+
onInput=${e => handleInstructTemplateChange(selectedTemplate,"fimTemplate",e.target.value)}
2939+
onValueChange=${() => {}}/>`}
2940+
</div>
2941+
<div id="advancedContextPlaceholders">
2942+
${getArrObjByName(templateList,selectedTemplate)?.affixes.fimTemplate !== undefined
2943+
? html`
2944+
<div>Use the <b>{fill}</b> placeholder to use the Fill-In-The-Middle template and start the prediction from that point.</div>
2945+
<div><b>{prefix}</b> represents the text before the placeholder, and <b>{suffix}</b> represents the text after it.</div>`
2946+
: html`
2947+
<div>This template doesn't have a Fill-In-The-Middle template.</div>
2948+
<div>You can use the <b>{predict}</b> placeholder to start the prediction from that point, but the model won't be aware of the text after the placeholder.</div>`}
2949+
</div>
2950+
</div>
29202951
</div>
29212952
29222953
@@ -3532,6 +3563,38 @@
35323563
);
35333564
}
35343565

3566+
/**
3567+
* Split a string with a RegExp separator an optionally limited number of times.
3568+
* (https://stackoverflow.com/a/64296576)
3569+
* @param {string} input
3570+
* @param {RegExp} separator
3571+
* @param {number} [limit] - If not included, splits the maximum times
3572+
* @returns {[string[], string[]]}
3573+
*/
3574+
function split(input, separator, limit) {
3575+
separator = new RegExp(separator, 'g');
3576+
limit = limit ?? -1;
3577+
3578+
const output = [];
3579+
const separators = [];
3580+
let finalIndex = 0;
3581+
3582+
while (limit--) {
3583+
const lastIndex = separator.lastIndex;
3584+
const search = separator.exec(input);
3585+
if (search === null) {
3586+
break;
3587+
}
3588+
finalIndex = separator.lastIndex;
3589+
output.push(input.slice(lastIndex, search.index));
3590+
separators.push(search[0]);
3591+
}
3592+
3593+
output.push(input.slice(finalIndex));
3594+
3595+
return [output, separators];
3596+
}
3597+
35353598
function useSessionState(sessionStorage, name, initialState) {
35363599
const savedState = useMemo(() => {
35373600
try {
@@ -4008,20 +4071,30 @@
40084071
// predicts one {fill} placeholder
40094072
async function fillPredict() {
40104073
const fillPlaceholder = "{fill}";
4074+
const predictPlaceholder = "{predict}";
40114075

4012-
let leftPromptChunks = [];
4013-
let rightPromptChunks = [];
4076+
let placeholderRegex = predictPlaceholder;
4077+
if (templates[selectedTemplate]?.fimTemplate !== undefined) {
4078+
placeholderRegex += `|${fillPlaceholder}`;
4079+
}
4080+
4081+
let leftPromptChunks = undefined;
4082+
let rightPromptChunks = undefined;
40144083
let foundFillPlaceholder = false;
4084+
let foundPredictPlaceholder = false;
40154085

40164086
for (let i = 0; i < promptChunks.length; i++) {
40174087
const chunk = promptChunks[i];
40184088
if (chunk.type !== 'user')
40194089
continue;
4020-
if (chunk.content.includes(fillPlaceholder)) {
4090+
4091+
if (chunk.content.includes(fillPlaceholder) || chunk.content.includes(predictPlaceholder)) {
40214092
// split the chunk in 2
4022-
foundFillPlaceholder = true;
4093+
let [sides, separators] = split(chunk.content, placeholderRegex, 1);
4094+
foundFillPlaceholder = separators[0] == fillPlaceholder;
4095+
foundPredictPlaceholder = separators[0] == predictPlaceholder;
40234096

4024-
let left = chunk.content.substring(0, chunk.content.indexOf(fillPlaceholder));
4097+
let left = sides[0];
40254098
if ((left.at(-2) != ' ' || left.at(-2) != '\t') && left.at(-1) == ' ') {
40264099
// This is most likely an unintentional mistake by the user.
40274100
left = left.substring(0, left.length - 1);
@@ -4031,7 +4104,7 @@
40314104
...(left ? [{ type: 'user', content: left }] : [])
40324105
];
40334106

4034-
let right = chunk.content.substring(chunk.content.indexOf(fillPlaceholder) + fillPlaceholder.length);
4107+
let right = sides[1];
40354108
rightPromptChunks = [
40364109
...(right ? [{ type: 'user', content: right }] : []),
40374110
...promptChunks.slice(i + 1, promptChunks.length - 1),
@@ -4040,10 +4113,21 @@
40404113
}
40414114
}
40424115

4043-
if (!foundFillPlaceholder)
4116+
if (!foundFillPlaceholder && !foundPredictPlaceholder)
40444117
return false;
40454118

4046-
const promptText = joinPrompt(leftPromptChunks);
4119+
let promptText;
4120+
if (foundFillPlaceholder) {
4121+
const prefix = joinPrompt(leftPromptChunks);
4122+
const suffix = joinPrompt(rightPromptChunks);
4123+
4124+
promptText = replacePlaceholders(templates[selectedTemplate].fimTemplate, {
4125+
'{prefix}': prefix,
4126+
'{suffix}': suffix
4127+
});
4128+
} else {
4129+
promptText = joinPrompt(leftPromptChunks);
4130+
}
40474131
const assembledWorldInfo = assembleWorldInfo(promptText);
40484132
const additionalContextPrompt = assembleAdditionalContext(assembledWorldInfo, promptText);
40494133
const finalPrompt = replacePlaceholders(additionalContextPrompt, templateReplacements);
@@ -4053,39 +4137,41 @@
40534137
let stop = false;
40544138
let omitChunk = false;
40554139

4056-
let wasReplacing = isReplacing;
4057-
isReplacing = false;
4058-
4059-
if (rightPromptChunks[0]) {
4060-
const trimmedChunk = chunk.content.replace(/^ /, "");
4061-
if (rightPromptChunks[0].content[0] === chunk.content[0] ||
4062-
rightPromptChunks[0].content[0] === trimmedChunk[0]
4063-
) {
4064-
omitChunk = true;
4065-
if (chunk.content[0] == ' ' && rightPromptChunks[0].content[0] != ' ') {
4066-
if (rightPromptChunks[0].type !== 'user')
4067-
console.warn("Predicted token changed, this shouldn't happen.");
4068-
rightPromptChunks[0].content = ' ' + rightPromptChunks[0].content;
4069-
}
4070-
if (rightPromptChunks[0].type === 'user') {
4071-
if (rightPromptChunks[0].content.startsWith(chunk.content)) {
4072-
rightPromptChunks[0].content = rightPromptChunks[0].content.substring(chunk.content.length);
4073-
if (!rightPromptChunks[0].content)
4074-
rightPromptChunks.shift();
4075-
omitChunk = false;
4076-
isReplacing = true;
4140+
if (!foundFillPlaceholder) {
4141+
let wasReplacing = isReplacing;
4142+
isReplacing = false;
4143+
4144+
if (rightPromptChunks[0]) {
4145+
const trimmedChunk = chunk.content.replace(/^ /, "");
4146+
if (rightPromptChunks[0].content[0] === chunk.content[0] ||
4147+
rightPromptChunks[0].content[0] === trimmedChunk[0]
4148+
) {
4149+
omitChunk = true;
4150+
if (chunk.content[0] == ' ' && rightPromptChunks[0].content[0] != ' ') {
4151+
if (rightPromptChunks[0].type !== 'user')
4152+
console.warn("Predicted token changed, this shouldn't happen.");
4153+
rightPromptChunks[0].content = ' ' + rightPromptChunks[0].content;
40774154
}
4155+
if (rightPromptChunks[0].type === 'user') {
4156+
if (rightPromptChunks[0].content.startsWith(chunk.content)) {
4157+
rightPromptChunks[0].content = rightPromptChunks[0].content.substring(chunk.content.length);
4158+
if (!rightPromptChunks[0].content)
4159+
rightPromptChunks.shift();
4160+
omitChunk = false;
4161+
isReplacing = true;
4162+
}
4163+
}
4164+
stop = true;
40784165
}
4079-
stop = true;
40804166
}
4081-
}
40824167

4083-
// When replacing, we continue until any mismatch.
4084-
if (wasReplacing && !isReplacing) {
4085-
if (rightPromptChunks.length !== 0)
4086-
return false;
4087-
// This means that the mismatch was caused by the end of the chunks to be replaced.
4088-
isReplacing = false;
4168+
// When replacing, we continue until any mismatch.
4169+
if (wasReplacing && !isReplacing) {
4170+
if (rightPromptChunks.length !== 0)
4171+
return false;
4172+
// This means that the mismatch was caused by the end of the chunks to be replaced.
4173+
isReplacing = false;
4174+
}
40894175
}
40904176

40914177
if (!omitChunk) {

0 commit comments

Comments
 (0)