|
595 | 595 | .instructmodal-edits .hbox {
|
596 | 596 | margin-top:8px;
|
597 | 597 | }
|
| 598 | +.instructmodal-edits .vbox { |
| 599 | + margin-top:8px; |
| 600 | +} |
598 | 601 |
|
599 | 602 |
|
600 | 603 |
|
|
2669 | 2672 | "sysSuf": "",
|
2670 | 2673 | "instPre": "",
|
2671 | 2674 | "instSuf": "",
|
| 2675 | + "fimTemplate": undefined, |
2672 | 2676 | }
|
2673 | 2677 | return { ...newState }
|
2674 | 2678 | })
|
|
2748 | 2752 | "sysSuf": template.affixes.sysSuf,
|
2749 | 2753 | "instPre": template.affixes.instPre,
|
2750 | 2754 | "instSuf": template.affixes.instSuf,
|
| 2755 | + "fimTemplate": template.affixes.fimTemplate, |
2751 | 2756 | }
|
2752 | 2757 | }
|
2753 | 2758 | return { ...newState }
|
|
2888 | 2893 | onInput=${e => handleInstructTemplateChange(selectedTemplate,"instPre",e.target.value)}
|
2889 | 2894 | onValueChange=${() => {}}/>
|
2890 | 2895 |
|
2891 |
| - <${InputBox} label="Instruct Suffix {/inst}" |
| 2896 | + <${InputBox} label="Instruct Suffix {/inst}" |
2892 | 2897 | placeholder="[/INST]"
|
2893 | 2898 | className=""
|
2894 | 2899 | tooltip=""
|
|
2908 | 2913 | onInput=${e => handleInstructTemplateChange(selectedTemplate,"sysPre",e.target.value)}
|
2909 | 2914 | onValueChange=${() => {}}/>
|
2910 | 2915 |
|
2911 |
| - <${InputBox} label="System Prompt Suffix {/sys}" |
| 2916 | + <${InputBox} label="System Prompt Suffix {/sys}" |
2912 | 2917 | placeholder="<</SYS>>\n\n"
|
2913 | 2918 | className=""
|
2914 | 2919 | tooltip=""
|
|
2917 | 2922 | onInput=${e => handleInstructTemplateChange(selectedTemplate,"sysSuf",e.target.value)}
|
2918 | 2923 | onValueChange=${() => {}}/>
|
2919 | 2924 | </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> |
2920 | 2951 | </div>
|
2921 | 2952 |
|
2922 | 2953 |
|
|
3532 | 3563 | );
|
3533 | 3564 | }
|
3534 | 3565 |
|
| 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 | + |
3535 | 3598 | function useSessionState(sessionStorage, name, initialState) {
|
3536 | 3599 | const savedState = useMemo(() => {
|
3537 | 3600 | try {
|
|
4008 | 4071 | // predicts one {fill} placeholder
|
4009 | 4072 | async function fillPredict() {
|
4010 | 4073 | const fillPlaceholder = "{fill}";
|
| 4074 | + const predictPlaceholder = "{predict}"; |
4011 | 4075 |
|
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; |
4014 | 4083 | let foundFillPlaceholder = false;
|
| 4084 | + let foundPredictPlaceholder = false; |
4015 | 4085 |
|
4016 | 4086 | for (let i = 0; i < promptChunks.length; i++) {
|
4017 | 4087 | const chunk = promptChunks[i];
|
4018 | 4088 | if (chunk.type !== 'user')
|
4019 | 4089 | continue;
|
4020 |
| - if (chunk.content.includes(fillPlaceholder)) { |
| 4090 | + |
| 4091 | + if (chunk.content.includes(fillPlaceholder) || chunk.content.includes(predictPlaceholder)) { |
4021 | 4092 | // 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; |
4023 | 4096 |
|
4024 |
| - let left = chunk.content.substring(0, chunk.content.indexOf(fillPlaceholder)); |
| 4097 | + let left = sides[0]; |
4025 | 4098 | if ((left.at(-2) != ' ' || left.at(-2) != '\t') && left.at(-1) == ' ') {
|
4026 | 4099 | // This is most likely an unintentional mistake by the user.
|
4027 | 4100 | left = left.substring(0, left.length - 1);
|
|
4031 | 4104 | ...(left ? [{ type: 'user', content: left }] : [])
|
4032 | 4105 | ];
|
4033 | 4106 |
|
4034 |
| - let right = chunk.content.substring(chunk.content.indexOf(fillPlaceholder) + fillPlaceholder.length); |
| 4107 | + let right = sides[1]; |
4035 | 4108 | rightPromptChunks = [
|
4036 | 4109 | ...(right ? [{ type: 'user', content: right }] : []),
|
4037 | 4110 | ...promptChunks.slice(i + 1, promptChunks.length - 1),
|
|
4040 | 4113 | }
|
4041 | 4114 | }
|
4042 | 4115 |
|
4043 |
| - if (!foundFillPlaceholder) |
| 4116 | + if (!foundFillPlaceholder && !foundPredictPlaceholder) |
4044 | 4117 | return false;
|
4045 | 4118 |
|
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 | + } |
4047 | 4131 | const assembledWorldInfo = assembleWorldInfo(promptText);
|
4048 | 4132 | const additionalContextPrompt = assembleAdditionalContext(assembledWorldInfo, promptText);
|
4049 | 4133 | const finalPrompt = replacePlaceholders(additionalContextPrompt, templateReplacements);
|
|
4053 | 4137 | let stop = false;
|
4054 | 4138 | let omitChunk = false;
|
4055 | 4139 |
|
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; |
4077 | 4154 | }
|
| 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; |
4078 | 4165 | }
|
4079 |
| - stop = true; |
4080 | 4166 | }
|
4081 |
| - } |
4082 | 4167 |
|
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 | + } |
4089 | 4175 | }
|
4090 | 4176 |
|
4091 | 4177 | if (!omitChunk) {
|
|
0 commit comments