TC: Allow setting null JSON schema (#4746) * TC: Allow setting empty JSON schema * Fix check for llamacpp schema * Handle grammar/schema for Aphrodite * Conditional include for guided_json * Update default presets with null value * Conditional include into payload for grammar/schema
Signed| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -44,7 +44,7 @@ | |||
| 44 | "guidance_scale": 1, | 44 | "guidance_scale": 1, |
| 45 | "negative_prompt": "", | 45 | "negative_prompt": "", |
| 46 | "grammar_string": "", | 46 | "grammar_string": "", |
| 47 | "json_schema": {}, | 47 | "json_schema": null, |
| 48 | "banned_tokens": "", | 48 | "banned_tokens": "", |
| 49 | "sampler_priority": [ | 49 | "sampler_priority": [ |
| 50 | "repetition_penalty", | 50 | "repetition_penalty", |
| @@ -25,7 +25,7 @@ import { getEventSourceStream } from './sse-stream.js'; | |||
| 25 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels } from './textgen-models.js'; | 25 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, loadAphroditeModels, loadDreamGenModels, loadFeatherlessModels, loadGenericModels, loadInfermaticAIModels, loadMancerModels, loadOllamaModels, loadOpenRouterModels, loadTabbyModels, loadTogetherAIModels, loadVllmModels } from './textgen-models.js'; |
| 26 | import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, TOKENIZER_SUPPORTED_KEY, getTextTokens, tokenizers } from './tokenizers.js'; | 26 | import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, TOKENIZER_SUPPORTED_KEY, getTextTokens, tokenizers } from './tokenizers.js'; |
| 27 | import { AbortReason } from './util/AbortReason.js'; | 27 | import { AbortReason } from './util/AbortReason.js'; |
| 28 | import { getSortableDelay, onlyUnique, arraysEqual } from './utils.js'; | 28 | import { getSortableDelay, onlyUnique, arraysEqual, isObject } from './utils.js'; |
| 29 | 29 | ||
| 30 | export const textgen_types = { | 30 | export const textgen_types = { |
| 31 | OOBA: 'ooba', | 31 | OOBA: 'ooba', |
| @@ -191,7 +191,7 @@ const settings = { | |||
| 191 | guidance_scale: 1, | 191 | guidance_scale: 1, |
| 192 | negative_prompt: '', | 192 | negative_prompt: '', |
| 193 | grammar_string: '', | 193 | grammar_string: '', |
| 194 | json_schema: {}, | 194 | json_schema: null, |
| 195 | banned_tokens: '', | 195 | banned_tokens: '', |
| 196 | global_banned_tokens: '', | 196 | global_banned_tokens: '', |
| 197 | send_banned_tokens: true, | 197 | send_banned_tokens: true, |
| @@ -851,11 +851,16 @@ export function initTextGenSettings() { | |||
| 851 | $('#tabby_json_schema').on('input', function () { | 851 | $('#tabby_json_schema').on('input', function () { |
| 852 | const json_schema_string = String($(this).val()); | 852 | const json_schema_string = String($(this).val()); |
| 853 | 853 | ||
| 854 | try { | 854 | if (json_schema_string) { |
| 855 | settings.json_schema = JSON.parse(json_schema_string || '{}'); | 855 | try { |
| 856 | } catch { | 856 | settings.json_schema = JSON.parse(json_schema_string); |
| 857 | // Ignore errors from here | 857 | } catch { |
| 858 | settings.json_schema = null; | ||
| 859 | } | ||
| 860 | } else { | ||
| 861 | settings.json_schema = null; | ||
| 858 | } | 862 | } |
| 863 | |||
| 859 | saveSettingsDebounced(); | 864 | saveSettingsDebounced(); |
| 860 | }); | 865 | }); |
| 861 | 866 | ||
| @@ -1152,8 +1157,8 @@ function setSettingByName(setting, value, trigger) { | |||
| 1152 | } | 1157 | } |
| 1153 | 1158 | ||
| 1154 | if ('json_schema' === setting) { | 1159 | if ('json_schema' === setting) { |
| 1155 | settings.json_schema = value ?? {}; | 1160 | settings.json_schema = value ?? null; |
| 1156 | $('#tabby_json_schema').val(JSON.stringify(settings.json_schema, null, 2)); | 1161 | $('#tabby_json_schema').val(value ? JSON.stringify(settings.json_schema, null, 2) : ''); |
| 1157 | return; | 1162 | return; |
| 1158 | } | 1163 | } |
| 1159 | 1164 | ||
| @@ -1555,8 +1560,8 @@ export async function getTextGenGenerationData(finalPrompt, maxTokens, isImperso | |||
| 1555 | 'seed': settings.seed >= 0 ? settings.seed : undefined, | 1560 | 'seed': settings.seed >= 0 ? settings.seed : undefined, |
| 1556 | 'guidance_scale': cfgValues?.guidanceScale?.value ?? settings.guidance_scale ?? 1, | 1561 | 'guidance_scale': cfgValues?.guidanceScale?.value ?? settings.guidance_scale ?? 1, |
| 1557 | 'negative_prompt': cfgValues?.negativePrompt ?? substituteParams(settings.negative_prompt) ?? '', | 1562 | 'negative_prompt': cfgValues?.negativePrompt ?? substituteParams(settings.negative_prompt) ?? '', |
| 1558 | 'grammar_string': settings.grammar_string, | 1563 | 'grammar_string': settings.grammar_string || undefined, |
| 1559 | 'json_schema': [TABBY, LLAMACPP].includes(settings.type) ? settings.json_schema : undefined, | 1564 | 'json_schema': [TABBY, LLAMACPP].includes(settings.type) && settings.json_schema ? settings.json_schema : undefined, |
| 1560 | // llama.cpp aliases. In case someone wants to use LM Studio as Text Completion API | 1565 | // llama.cpp aliases. In case someone wants to use LM Studio as Text Completion API |
| 1561 | 'repeat_penalty': settings.rep_pen, | 1566 | 'repeat_penalty': settings.rep_pen, |
| 1562 | 'repeat_last_n': settings.rep_pen_range, | 1567 | 'repeat_last_n': settings.rep_pen_range, |
| @@ -1597,8 +1602,8 @@ export async function getTextGenGenerationData(finalPrompt, maxTokens, isImperso | |||
| 1597 | 'min_tokens': settings.min_length, | 1602 | 'min_tokens': settings.min_length, |
| 1598 | 'skip_special_tokens': settings.skip_special_tokens, | 1603 | 'skip_special_tokens': settings.skip_special_tokens, |
| 1599 | 'spaces_between_special_tokens': settings.spaces_between_special_tokens, | 1604 | 'spaces_between_special_tokens': settings.spaces_between_special_tokens, |
| 1600 | 'guided_grammar': settings.grammar_string, | 1605 | 'guided_grammar': settings.grammar_string || undefined, |
| 1601 | 'guided_json': settings.json_schema, | 1606 | 'guided_json': settings.json_schema || undefined, |
| 1602 | 'early_stopping': false, // hacks | 1607 | 'early_stopping': false, // hacks |
| 1603 | 'include_stop_str_in_output': false, | 1608 | 'include_stop_str_in_output': false, |
| 1604 | 'dynatemp_min': dynatemp ? settings.min_temp : undefined, | 1609 | 'dynatemp_min': dynatemp ? settings.min_temp : undefined, |
| @@ -1622,7 +1627,7 @@ export async function getTextGenGenerationData(finalPrompt, maxTokens, isImperso | |||
| 1622 | } | 1627 | } |
| 1623 | 1628 | ||
| 1624 | if (settings.type === KOBOLDCPP) { | 1629 | if (settings.type === KOBOLDCPP) { |
| 1625 | params.grammar = settings.grammar_string; | 1630 | params.grammar = settings.grammar_string || undefined; |
| 1626 | params.trim_stop = true; | 1631 | params.trim_stop = true; |
| 1627 | } | 1632 | } |
| 1628 | 1633 | ||
| @@ -1691,17 +1696,19 @@ export async function getTextGenGenerationData(finalPrompt, maxTokens, isImperso | |||
| 1691 | } | 1696 | } |
| 1692 | } | 1697 | } |
| 1693 | 1698 | ||
| 1694 | await eventSource.emit(event_types.TEXT_COMPLETION_SETTINGS_READY, params); | ||
| 1695 | |||
| 1696 | // Grammar conflicts with with json_schema | 1699 | // Grammar conflicts with with json_schema |
| 1697 | if (settings.type === LLAMACPP) { | 1700 | if ([LLAMACPP, APHRODITE].includes(settings.type)) { |
| 1698 | if (params.json_schema && Object.keys(params.json_schema).length > 0) { | 1701 | if (settings.json_schema && isObject(settings.json_schema)) { |
| 1699 | delete params.grammar_string; | 1702 | delete params.grammar_string; |
| 1700 | delete params.grammar; | 1703 | delete params.grammar; |
| 1704 | delete params.guided_grammar; | ||
| 1701 | } else { | 1705 | } else { |
| 1702 | delete params.json_schema; | 1706 | delete params.json_schema; |
| 1707 | delete params.guided_json; | ||
| 1703 | } | 1708 | } |
| 1704 | } | 1709 | } |
| 1705 | 1710 | ||
| 1711 | await eventSource.emit(event_types.TEXT_COMPLETION_SETTINGS_READY, params); | ||
| 1712 | |||
| 1706 | return params; | 1713 | return params; |
| 1707 | } | 1714 | } |
| @@ -100,7 +100,7 @@ export const navigation_option = { | |||
| 100 | * @param {any} item The item to check. | 100 | * @param {any} item The item to check. |
| 101 | * @returns {boolean} True if the item is an object, false otherwise. | 101 | * @returns {boolean} True if the item is an object, false otherwise. |
| 102 | */ | 102 | */ |
| 103 | function isObject(item) { | 103 | export function isObject(item) { |
| 104 | return (item && typeof item === 'object' && !Array.isArray(item)); | 104 | return (item && typeof item === 'object' && !Array.isArray(item)); |
| 105 | } | 105 | } |
| 106 | 106 | ||