mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Pollinations - Text (#3985)
* [wip] Pollinations for text * Implement generate API request * Determine Pollinations model tools via models list * Add Pollinations option to /model command * Add Pollinations support to caption * Update link to pollinations site * Fix type errors in openai.js * Fix API connection test to use AbortController for request cancellation * Remove hard coded list of pollinations vision models * Remove openai-audio from captioning models
This commit is contained in:
1
public/img/pollinations.svg
Normal file
1
public/img/pollinations.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 34 KiB |
@ -974,7 +974,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai">
|
||||
<div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai,pollinations">
|
||||
<div class="range-block-title justifyLeft" data-i18n="Seed">
|
||||
Seed
|
||||
</div>
|
||||
@ -1977,7 +1977,7 @@
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21,xai">
|
||||
<div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21,xai,pollinations">
|
||||
<label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
|
||||
<input id="openai_function_calling" type="checkbox" />
|
||||
<span data-i18n="Enable function calling">Enable function calling</span>
|
||||
@ -1987,7 +1987,7 @@
|
||||
<span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,openrouter,mistralai,makersuite,claude,custom,01ai,xai">
|
||||
<div class="range-block" data-source="openai,openrouter,mistralai,makersuite,claude,custom,01ai,xai,pollinations">
|
||||
<label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
|
||||
<input id="openai_image_inlining" type="checkbox" />
|
||||
<span data-i18n="Send inline images">Send inline images</span>
|
||||
@ -1999,7 +1999,7 @@
|
||||
<code><i class="fa-solid fa-wand-magic-sparkles"></i></code>
|
||||
<span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai">
|
||||
<div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations">
|
||||
<div class="flex-container oneline-dropdown">
|
||||
<label for="openai_inline_image_quality" data-i18n="Inline Image Quality">
|
||||
Inline Image Quality
|
||||
@ -2057,7 +2057,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,openrouter">
|
||||
<div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,openrouter,pollinations">
|
||||
<div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models.">
|
||||
<label for="openai_reasoning_effort">
|
||||
<span data-i18n="Reasoning Effort">Reasoning Effort</span>
|
||||
@ -2770,6 +2770,7 @@
|
||||
<option value="nanogpt">NanoGPT</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="perplexity">Perplexity</option>
|
||||
<option value="pollinations">Pollinations</option>
|
||||
<option value="scale">Scale</option>
|
||||
<option value="windowai">Window AI</option>
|
||||
<option value="xai">xAI (Grok)</option>
|
||||
@ -3480,6 +3481,21 @@
|
||||
<option value="grok-beta">grok-beta</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="pollinations_form" data-source="pollinations">
|
||||
<h4 data-i18n="Pollinations Model">Pollinations Model</h4>
|
||||
<select id="model_pollinations_select">
|
||||
<!-- Populated by JavaScript -->
|
||||
</select>
|
||||
<div class="info-block hint">
|
||||
<a href="https://pollinations.ai/" target="_blank" rel="noopener noreferrer" data-i18n="Provided free of charge by Pollinations.AI">
|
||||
Provided free of charge by Pollinations.AI
|
||||
</a>
|
||||
<br>
|
||||
<span data-i18n="Avoid sending sensitive information. Provider's outputs may include ads.">
|
||||
Avoid sending sensitive information. Provider's outputs may include ads.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="prompt_post_porcessing_form" data-source="custom,openrouter">
|
||||
<h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4>
|
||||
<select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API.">
|
||||
|
@ -4811,7 +4811,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
name2: name2,
|
||||
charDescription: description,
|
||||
charPersonality: personality,
|
||||
Scenario: scenario,
|
||||
scenario: scenario,
|
||||
worldInfoBefore: worldInfoBefore,
|
||||
worldInfoAfter: worldInfoAfter,
|
||||
extensionPrompts: extension_prompts,
|
||||
|
@ -86,15 +86,15 @@ class Prompt {
|
||||
* @param {string} param0.identifier - The unique identifier of the prompt.
|
||||
* @param {string} param0.role - The role associated with the prompt.
|
||||
* @param {string} param0.content - The content of the prompt.
|
||||
* @param {string} param0.name - The name of the prompt.
|
||||
* @param {boolean} param0.system_prompt - Indicates if the prompt is a system prompt.
|
||||
* @param {string} param0.position - The position of the prompt in the prompt list.
|
||||
* @param {number} param0.injection_position - The insert position of the prompt.
|
||||
* @param {number} param0.injection_depth - The depth of the prompt in the chat.
|
||||
* @param {boolean} param0.forbid_overrides - Indicates if the prompt should not be overridden.
|
||||
* @param {boolean} param0.extension - Prompt is added by an extension.
|
||||
* @param {string} [param0.name] - The name of the prompt.
|
||||
* @param {boolean} [param0.system_prompt] - Indicates if the prompt is a system prompt.
|
||||
* @param {string} [param0.position] - The position of the prompt in the prompt list.
|
||||
* @param {number} [param0.injection_position] - The insert position of the prompt.
|
||||
* @param {number} [param0.injection_depth] - The depth of the prompt in the chat.
|
||||
* @param {boolean} [param0.forbid_overrides] - Indicates if the prompt should not be overridden.
|
||||
* @param {boolean} [param0.extension] - Prompt is added by an extension.
|
||||
*/
|
||||
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension } = {}) {
|
||||
constructor({ identifier, role, content, name, system_prompt, position, injection_depth, injection_position, forbid_overrides, extension }) {
|
||||
this.identifier = identifier;
|
||||
this.role = role;
|
||||
this.content = content;
|
||||
|
@ -410,6 +410,7 @@ function RA_autoconnect(PrevApi) {
|
||||
|| (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)
|
||||
|| (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)
|
||||
|| (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI)
|
||||
|| (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)
|
||||
|| (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
|
||||
) {
|
||||
$('#api_button_openai').trigger('click');
|
||||
|
@ -448,7 +448,7 @@ jQuery(async function () {
|
||||
}
|
||||
|
||||
// Custom API doesn't need additional checks
|
||||
if (api === 'custom') {
|
||||
if (api === 'custom' || api === 'pollinations') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="ooba" data-i18n="Text Generation WebUI (oobabooga)">Text Generation WebUI (oobabooga)</option>
|
||||
<option value="pollinations">Pollinations</option>
|
||||
<option value="vllm">vLLM</option>
|
||||
<option value="xai">xAI (Grok)</option>
|
||||
</select>
|
||||
@ -151,6 +152,18 @@
|
||||
<option data-type="custom" value="custom_current" data-i18n="currently_selected">[Currently selected]</option>
|
||||
<option data-type="xai" value="grok-2-vision-1212">grok-2-vision-1212</option>
|
||||
<option data-type="xai" value="grok-vision-beta">grok-vision-beta</option>
|
||||
<option data-type="pollinations" value="openai">openai</option>
|
||||
<option data-type="pollinations" value="openai-fast">openai-fast</option>
|
||||
<option data-type="pollinations" value="openai-large">openai-large</option>
|
||||
<option data-type="pollinations" value="openai-roblox">openai-roblox</option>
|
||||
<option data-type="pollinations" value="mistral">mistral</option>
|
||||
<option data-type="pollinations" value="unity">unity</option>
|
||||
<option data-type="pollinations" value="mirexa">mirexa</option>
|
||||
<option data-type="pollinations" value="searchgpt">searchgpt</option>
|
||||
<option data-type="pollinations" value="evil">evil</option>
|
||||
<option data-type="pollinations" value="phi">phi</option>
|
||||
<option data-type="pollinations" value="sur">sur</option>
|
||||
<option data-type="pollinations" value="bidara">bidara</option>
|
||||
</select>
|
||||
</div>
|
||||
<div data-type="ollama">
|
||||
|
@ -185,6 +185,7 @@ export const chat_completion_sources = {
|
||||
NANOGPT: 'nanogpt',
|
||||
DEEPSEEK: 'deepseek',
|
||||
XAI: 'xai',
|
||||
POLLINATIONS: 'pollinations',
|
||||
};
|
||||
|
||||
const character_names_behavior = {
|
||||
@ -268,6 +269,7 @@ export const settingsToUpdate = {
|
||||
deepseek_model: ['#model_deepseek_select', 'deepseek_model', false],
|
||||
zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false],
|
||||
xai_model: ['#model_xai_select', 'xai_model', false],
|
||||
pollinations_model: ['#model_pollinations_select', 'pollinations_model', false],
|
||||
custom_model: ['#custom_model_id', 'custom_model', false],
|
||||
custom_url: ['#custom_api_url_text', 'custom_url', false],
|
||||
custom_include_body: ['#custom_include_body', 'custom_include_body', false],
|
||||
@ -357,6 +359,7 @@ const default_settings = {
|
||||
zerooneai_model: 'yi-large',
|
||||
deepseek_model: 'deepseek-chat',
|
||||
xai_model: 'grok-3-beta',
|
||||
pollinations_model: 'openai',
|
||||
custom_model: '',
|
||||
custom_url: '',
|
||||
custom_include_body: '',
|
||||
@ -438,6 +441,7 @@ const oai_settings = {
|
||||
zerooneai_model: 'yi-large',
|
||||
deepseek_model: 'deepseek-chat',
|
||||
xai_model: 'grok-3-beta',
|
||||
pollinations_model: 'openai',
|
||||
custom_model: '',
|
||||
custom_url: '',
|
||||
custom_include_body: '',
|
||||
@ -1181,7 +1185,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm
|
||||
* Combines system prompts with prompt manager prompts
|
||||
*
|
||||
* @param {Object} options - An object with optional settings.
|
||||
* @param {string} options.Scenario - The scenario or context of the dialogue.
|
||||
* @param {string} options.scenario - The scenario or context of the dialogue.
|
||||
* @param {string} options.charPersonality - Description of the character's personality.
|
||||
* @param {string} options.name2 - The second name to be used in the messages.
|
||||
* @param {string} options.worldInfoBefore - The world info to be added before the main conversation.
|
||||
@ -1195,8 +1199,8 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm
|
||||
* @param {string} options.personaDescription
|
||||
* @returns {Promise<Object>} prompts - The prepared and merged system and user-defined prompts.
|
||||
*/
|
||||
async function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription }) {
|
||||
const scenarioText = Scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : '';
|
||||
async function preparePromptsForChatCompletion({ scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription }) {
|
||||
const scenarioText = scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : '';
|
||||
const charPersonalityText = charPersonality && oai_settings.personality_format ? substituteParams(oai_settings.personality_format) : '';
|
||||
const groupNudge = substituteParams(oai_settings.group_nudge_prompt);
|
||||
const impersonationPrompt = oai_settings.impersonation_prompt ? substituteParams(oai_settings.impersonation_prompt) : '';
|
||||
@ -1352,7 +1356,7 @@ async function preparePromptsForChatCompletion({ Scenario, charPersonality, name
|
||||
* @param {string} content.name2 - The second name to be used in the messages.
|
||||
* @param {string} content.charDescription - Description of the character.
|
||||
* @param {string} content.charPersonality - Description of the character's personality.
|
||||
* @param {string} content.Scenario - The scenario or context of the dialogue.
|
||||
* @param {string} content.scenario - The scenario or context of the dialogue.
|
||||
* @param {string} content.worldInfoBefore - The world info to be added before the main conversation.
|
||||
* @param {string} content.worldInfoAfter - The world info to be added after the main conversation.
|
||||
* @param {string} content.bias - The bias to be added in the conversation.
|
||||
@ -1373,7 +1377,7 @@ export async function prepareOpenAIMessages({
|
||||
name2,
|
||||
charDescription,
|
||||
charPersonality,
|
||||
Scenario,
|
||||
scenario,
|
||||
worldInfoBefore,
|
||||
worldInfoAfter,
|
||||
bias,
|
||||
@ -1400,21 +1404,18 @@ export async function prepareOpenAIMessages({
|
||||
try {
|
||||
// Merge markers and ordered user prompts with system prompts
|
||||
const prompts = await preparePromptsForChatCompletion({
|
||||
Scenario,
|
||||
scenario,
|
||||
charPersonality,
|
||||
name2,
|
||||
worldInfoBefore,
|
||||
worldInfoAfter,
|
||||
charDescription,
|
||||
quietPrompt,
|
||||
quietImage,
|
||||
bias,
|
||||
extensionPrompts,
|
||||
systemPromptOverride,
|
||||
jailbreakPromptOverride,
|
||||
personaDescription,
|
||||
messages,
|
||||
messageExamples,
|
||||
});
|
||||
|
||||
// Fill the chat completion with as much context as the budget allows
|
||||
@ -1660,6 +1661,8 @@ export function getChatCompletionModel(source = null) {
|
||||
return oai_settings.deepseek_model;
|
||||
case chat_completion_sources.XAI:
|
||||
return oai_settings.xai_model;
|
||||
case chat_completion_sources.POLLINATIONS:
|
||||
return oai_settings.pollinations_model;
|
||||
default:
|
||||
console.error(`Unknown chat completion source: ${activeSource}`);
|
||||
return '';
|
||||
@ -1842,6 +1845,24 @@ function saveModelList(data) {
|
||||
|
||||
$('#model_deepseek_select').val(oai_settings.deepseek_model).trigger('change');
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) {
|
||||
$('#model_pollinations_select').empty();
|
||||
model_list.forEach((model) => {
|
||||
$('#model_pollinations_select').append(
|
||||
$('<option>', {
|
||||
value: model.id,
|
||||
text: model.id,
|
||||
}));
|
||||
});
|
||||
|
||||
const selectedModel = model_list.find(model => model.id === oai_settings.pollinations_model);
|
||||
if (model_list.length > 0 && (!selectedModel || !oai_settings.pollinations_model)) {
|
||||
oai_settings.pollinations_model = model_list[0].id;
|
||||
}
|
||||
|
||||
$('#model_pollinations_select').val(oai_settings.pollinations_model).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
|
||||
@ -1954,6 +1975,7 @@ function getReasoningEffort() {
|
||||
chat_completion_sources.CUSTOM,
|
||||
chat_completion_sources.XAI,
|
||||
chat_completion_sources.OPENROUTER,
|
||||
chat_completion_sources.POLLINATIONS,
|
||||
];
|
||||
|
||||
if (!reasoningEffortSources.includes(oai_settings.chat_completion_source)) {
|
||||
@ -2009,6 +2031,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT;
|
||||
const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK;
|
||||
const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI;
|
||||
const isPollinations = oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS;
|
||||
const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
|
||||
const isQuiet = type === 'quiet';
|
||||
const isImpersonate = type === 'impersonate';
|
||||
@ -2211,7 +2234,15 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano || isXAI) && oai_settings.seed >= 0) {
|
||||
if (isPollinations) {
|
||||
delete generate_data.temperature;
|
||||
delete generate_data.top_p;
|
||||
delete generate_data.frequency_penalty;
|
||||
delete generate_data.presence_penalty;
|
||||
delete generate_data.max_tokens;
|
||||
}
|
||||
|
||||
if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano || isXAI || isPollinations) && oai_settings.seed >= 0) {
|
||||
generate_data['seed'] = oai_settings.seed;
|
||||
}
|
||||
|
||||
@ -2407,13 +2438,14 @@ function parseOpenAIChatLogprobs(logprobs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @type {({ token: string, logprob: number }) => [string, number]} */
|
||||
/** @type {(x: { token: string, logprob: number }) => [string, number]} */
|
||||
const toTuple = (x) => [x.token, x.logprob];
|
||||
|
||||
return content.map(({ token, logprob, top_logprobs }) => {
|
||||
// Add the chosen token to top_logprobs if it's not already there, then
|
||||
// convert to a list of [token, logprob] pairs
|
||||
const chosenTopToken = top_logprobs.some((top) => token === top.token);
|
||||
/** @type {import('./logprobs.js').Candidate[]} */
|
||||
const topLogprobs = chosenTopToken
|
||||
? top_logprobs.map(toTuple)
|
||||
: [...top_logprobs.map(toTuple), [token, logprob]];
|
||||
@ -2438,6 +2470,7 @@ function parseOpenAITextLogprobs(logprobs) {
|
||||
return tokens.map((token, i) => {
|
||||
// Add the chosen token to top_logprobs if it's not already there, then
|
||||
// convert to a list of [token, logprob] pairs
|
||||
/** @type {any[]} */
|
||||
const topLogprobs = top_logprobs[i] ? Object.entries(top_logprobs[i]) : [];
|
||||
const chosenTopToken = topLogprobs.some(([topToken]) => token === topToken);
|
||||
if (!chosenTopToken) {
|
||||
@ -3262,7 +3295,7 @@ function loadOpenAISettings(data, settings) {
|
||||
openai_setting_names = arr_holder;
|
||||
|
||||
oai_settings.preset_settings_openai = settings.preset_settings_openai;
|
||||
$(`#settings_preset_openai option[value=${openai_setting_names[oai_settings.preset_settings_openai]}]`).attr('selected', true);
|
||||
$(`#settings_preset_openai option[value=${openai_setting_names[oai_settings.preset_settings_openai]}]`).prop('selected', true);
|
||||
|
||||
oai_settings.temp_openai = settings.temp_openai ?? default_settings.temp_openai;
|
||||
oai_settings.freq_pen_openai = settings.freq_pen_openai ?? default_settings.freq_pen_openai;
|
||||
@ -3300,6 +3333,7 @@ function loadOpenAISettings(data, settings) {
|
||||
oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model;
|
||||
oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model;
|
||||
oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model;
|
||||
oai_settings.pollinations_model = settings.pollinations_model ?? default_settings.pollinations_model;
|
||||
oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
|
||||
oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url;
|
||||
oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body;
|
||||
@ -3363,30 +3397,32 @@ function loadOpenAISettings(data, settings) {
|
||||
$(`#openai_inline_image_quality option[value="${oai_settings.inline_image_quality}"]`).prop('selected', true);
|
||||
|
||||
$('#model_openai_select').val(oai_settings.openai_model);
|
||||
$(`#model_openai_select option[value="${oai_settings.openai_model}"`).attr('selected', true);
|
||||
$(`#model_openai_select option[value="${oai_settings.openai_model}"`).prop('selected', true);
|
||||
$('#model_claude_select').val(oai_settings.claude_model);
|
||||
$(`#model_claude_select option[value="${oai_settings.claude_model}"`).attr('selected', true);
|
||||
$(`#model_claude_select option[value="${oai_settings.claude_model}"`).prop('selected', true);
|
||||
$('#model_windowai_select').val(oai_settings.windowai_model);
|
||||
$(`#model_windowai_select option[value="${oai_settings.windowai_model}"`).attr('selected', true);
|
||||
$(`#model_windowai_select option[value="${oai_settings.windowai_model}"`).prop('selected', true);
|
||||
$('#model_google_select').val(oai_settings.google_model);
|
||||
$(`#model_google_select option[value="${oai_settings.google_model}"`).attr('selected', true);
|
||||
$(`#model_google_select option[value="${oai_settings.google_model}"`).prop('selected', true);
|
||||
$('#model_ai21_select').val(oai_settings.ai21_model);
|
||||
$(`#model_ai21_select option[value="${oai_settings.ai21_model}"`).attr('selected', true);
|
||||
$(`#model_ai21_select option[value="${oai_settings.ai21_model}"`).prop('selected', true);
|
||||
$('#model_mistralai_select').val(oai_settings.mistralai_model);
|
||||
$(`#model_mistralai_select option[value="${oai_settings.mistralai_model}"`).attr('selected', true);
|
||||
$(`#model_mistralai_select option[value="${oai_settings.mistralai_model}"`).prop('selected', true);
|
||||
$('#model_cohere_select').val(oai_settings.cohere_model);
|
||||
$(`#model_cohere_select option[value="${oai_settings.cohere_model}"`).attr('selected', true);
|
||||
$(`#model_cohere_select option[value="${oai_settings.cohere_model}"`).prop('selected', true);
|
||||
$('#model_perplexity_select').val(oai_settings.perplexity_model);
|
||||
$(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).attr('selected', true);
|
||||
$(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).prop('selected', true);
|
||||
$('#model_groq_select').val(oai_settings.groq_model);
|
||||
$(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true);
|
||||
$(`#model_groq_select option[value="${oai_settings.groq_model}"`).prop('selected', true);
|
||||
$('#model_nanogpt_select').val(oai_settings.nanogpt_model);
|
||||
$(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).attr('selected', true);
|
||||
$(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).prop('selected', true);
|
||||
$('#model_deepseek_select').val(oai_settings.deepseek_model);
|
||||
$(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true);
|
||||
$('#model_01ai_select').val(oai_settings.zerooneai_model);
|
||||
$('#model_xai_select').val(oai_settings.xai_model);
|
||||
$(`#model_xai_select option[value="${oai_settings.xai_model}"`).attr('selected', true);
|
||||
$(`#model_xai_select option[value="${oai_settings.xai_model}"`).prop('selected', true);
|
||||
$('#model_pollinations_select').val(oai_settings.pollinations_model);
|
||||
$(`#model_pollinations_select option[value="${oai_settings.pollinations_model}"`).prop('selected', true);
|
||||
$('#custom_model_id').val(oai_settings.custom_model);
|
||||
$('#custom_api_url_text').val(oai_settings.custom_url);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context);
|
||||
@ -3492,7 +3528,7 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#chat_completion_source').val(oai_settings.chat_completion_source).trigger('change');
|
||||
$('#oai_max_context_unlocked').prop('checked', oai_settings.max_context_unlocked);
|
||||
$('#custom_prompt_post_processing').val(oai_settings.custom_prompt_post_processing);
|
||||
$(`#custom_prompt_post_processing option[value="${oai_settings.custom_prompt_post_processing}"]`).attr('selected', true);
|
||||
$(`#custom_prompt_post_processing option[value="${oai_settings.custom_prompt_post_processing}"]`).prop('selected', true);
|
||||
}
|
||||
|
||||
function setNamesBehaviorControls() {
|
||||
@ -3667,6 +3703,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
groq_model: settings.groq_model,
|
||||
zerooneai_model: settings.zerooneai_model,
|
||||
xai_model: settings.xai_model,
|
||||
pollinations_model: settings.pollinations_model,
|
||||
custom_model: settings.custom_model,
|
||||
custom_url: settings.custom_url,
|
||||
custom_include_body: settings.custom_include_body,
|
||||
@ -3739,7 +3776,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
oai_settings.preset_settings_openai = data.name;
|
||||
const value = openai_setting_names[data.name];
|
||||
Object.assign(openai_settings[value], presetBody);
|
||||
$(`#settings_preset_openai option[value="${value}"]`).attr('selected', true);
|
||||
$(`#settings_preset_openai option[value="${value}"]`).prop('selected', true);
|
||||
if (triggerUi) $('#settings_preset_openai').trigger('change');
|
||||
}
|
||||
else {
|
||||
@ -3747,7 +3784,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
openai_setting_names[data.name] = openai_settings.length - 1;
|
||||
const option = document.createElement('option');
|
||||
option.selected = true;
|
||||
option.value = openai_settings.length - 1;
|
||||
option.value = String(openai_settings.length - 1);
|
||||
option.innerText = data.name;
|
||||
if (triggerUi) $('#settings_preset_openai').append(option).trigger('change');
|
||||
}
|
||||
@ -3955,14 +3992,14 @@ async function onPresetImportFileChange(e) {
|
||||
oai_settings.preset_settings_openai = data.name;
|
||||
const value = openai_setting_names[data.name];
|
||||
Object.assign(openai_settings[value], presetBody);
|
||||
$(`#settings_preset_openai option[value="${value}"]`).attr('selected', true);
|
||||
$(`#settings_preset_openai option[value="${value}"]`).prop('selected', true);
|
||||
$('#settings_preset_openai').trigger('change');
|
||||
} else {
|
||||
openai_settings.push(presetBody);
|
||||
openai_setting_names[data.name] = openai_settings.length - 1;
|
||||
const option = document.createElement('option');
|
||||
option.selected = true;
|
||||
option.value = openai_settings.length - 1;
|
||||
option.value = String(openai_settings.length - 1);
|
||||
option.innerText = data.name;
|
||||
$('#settings_preset_openai').append(option).trigger('change');
|
||||
}
|
||||
@ -4067,7 +4104,7 @@ async function onDeletePresetClick() {
|
||||
if (Object.keys(openai_setting_names).length) {
|
||||
oai_settings.preset_settings_openai = Object.keys(openai_setting_names)[0];
|
||||
const newValue = openai_setting_names[oai_settings.preset_settings_openai];
|
||||
$(`#settings_preset_openai option[value="${newValue}"]`).attr('selected', true);
|
||||
$(`#settings_preset_openai option[value="${newValue}"]`).prop('selected', true);
|
||||
$('#settings_preset_openai').trigger('change');
|
||||
}
|
||||
|
||||
@ -4099,7 +4136,7 @@ async function onLogitBiasPresetDeleteClick() {
|
||||
|
||||
if (Object.keys(oai_settings.bias_presets).length) {
|
||||
oai_settings.bias_preset_selected = Object.keys(oai_settings.bias_presets)[0];
|
||||
$(`#openai_logit_bias_preset option[value="${oai_settings.bias_preset_selected}"]`).attr('selected', true);
|
||||
$(`#openai_logit_bias_preset option[value="${oai_settings.bias_preset_selected}"]`).prop('selected', true);
|
||||
$('#openai_logit_bias_preset').trigger('change');
|
||||
}
|
||||
|
||||
@ -4465,6 +4502,11 @@ async function onModelChange() {
|
||||
$('#custom_model_id').val(value).trigger('input');
|
||||
}
|
||||
|
||||
if (value && $(this).is('#model_pollinations_select')) {
|
||||
console.log('Pollinations model changed to', value);
|
||||
oai_settings.pollinations_model = value;
|
||||
}
|
||||
|
||||
if ($(this).is('#model_xai_select')) {
|
||||
console.log('XAI model changed to', value);
|
||||
oai_settings.xai_model = value;
|
||||
@ -4705,6 +4747,18 @@ async function onModelChange() {
|
||||
$('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) {
|
||||
if (oai_settings.max_context_unlocked) {
|
||||
$('#openai_max_context').attr('max', unlocked_max);
|
||||
} else {
|
||||
$('#openai_max_context').attr('max', max_128k);
|
||||
}
|
||||
|
||||
oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
$('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {
|
||||
if (oai_settings.max_context_unlocked) {
|
||||
$('#openai_max_context').attr('max', unlocked_max);
|
||||
@ -5047,6 +5101,9 @@ function toggleChatCompletionForms() {
|
||||
else if (oai_settings.chat_completion_source == chat_completion_sources.XAI) {
|
||||
$('#model_xai_select').trigger('change');
|
||||
}
|
||||
else if (oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS) {
|
||||
$('#model_pollinations_select').trigger('change');
|
||||
}
|
||||
$('[data-source]').each(function () {
|
||||
const validSources = $(this).data('source').split(',');
|
||||
$(this).toggle(validSources.includes(oai_settings.chat_completion_source));
|
||||
@ -5061,7 +5118,7 @@ async function testApiConnection() {
|
||||
}
|
||||
|
||||
try {
|
||||
const reply = await sendOpenAIRequest('quiet', [{ 'role': 'user', 'content': 'Hi' }]);
|
||||
const reply = await sendOpenAIRequest('quiet', [{ 'role': 'user', 'content': 'Hi' }], new AbortController().signal);
|
||||
console.log(reply);
|
||||
toastr.success(t`API connection successful!`);
|
||||
}
|
||||
@ -5186,6 +5243,8 @@ export function isImageInliningSupported() {
|
||||
return visionSupportedModels.some(model => oai_settings.cohere_model.includes(model));
|
||||
case chat_completion_sources.XAI:
|
||||
return visionSupportedModels.some(model => oai_settings.xai_model.includes(model));
|
||||
case chat_completion_sources.POLLINATIONS:
|
||||
return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -5258,8 +5317,8 @@ $('#save_proxy').on('click', async function () {
|
||||
toastr.success(t`Proxy Saved`);
|
||||
if ($('#openai_proxy_preset').val() !== presetName) {
|
||||
const option = document.createElement('option');
|
||||
option.text = presetName;
|
||||
option.value = presetName;
|
||||
option.text = String(presetName);
|
||||
option.value = String(presetName);
|
||||
|
||||
$('#openai_proxy_preset').append(option);
|
||||
}
|
||||
@ -5784,6 +5843,7 @@ export function initOpenAI() {
|
||||
$('#model_01ai_select').on('change', onModelChange);
|
||||
$('#model_custom_select').on('change', onModelChange);
|
||||
$('#model_xai_select').on('change', onModelChange);
|
||||
$('#model_pollinations_select').on('change', onModelChange);
|
||||
$('#settings_preset_openai').on('change', onSettingsPresetChange);
|
||||
$('#new_oai_preset').on('click', onNewPresetClick);
|
||||
$('#delete_oai_preset').on('click', onDeletePresetClick);
|
||||
|
@ -4136,6 +4136,7 @@ function getModelOptions(quiet) {
|
||||
{ id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI },
|
||||
{ id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK },
|
||||
{ id: 'model_xai_select', api: 'openai', type: chat_completion_sources.XAI },
|
||||
{ id: 'model_pollinations_select', api: 'openai', type: chat_completion_sources.POLLINATIONS },
|
||||
{ id: 'model_novel_select', api: 'novel', type: null },
|
||||
{ id: 'horde_model', api: 'koboldhorde', type: null },
|
||||
];
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { DOMPurify } from '../lib.js';
|
||||
|
||||
import { addOneMessage, chat, event_types, eventSource, main_api, saveChatConditional, system_avatar, systemUserName } from '../script.js';
|
||||
import { chat_completion_sources, oai_settings } from './openai.js';
|
||||
import { chat_completion_sources, model_list, oai_settings } from './openai.js';
|
||||
import { Popup } from './popup.js';
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
@ -575,6 +575,13 @@ export class ToolManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS && Array.isArray(model_list)) {
|
||||
const currentModel = model_list.find(model => model.id === oai_settings.pollinations_model);
|
||||
if (currentModel) {
|
||||
return currentModel.tools;
|
||||
}
|
||||
}
|
||||
|
||||
const supportedSources = [
|
||||
chat_completion_sources.OPENAI,
|
||||
chat_completion_sources.CUSTOM,
|
||||
@ -587,6 +594,7 @@ export class ToolManager {
|
||||
chat_completion_sources.MAKERSUITE,
|
||||
chat_completion_sources.AI21,
|
||||
chat_completion_sources.XAI,
|
||||
chat_completion_sources.POLLINATIONS,
|
||||
];
|
||||
return supportedSources.includes(oai_settings.chat_completion_source);
|
||||
}
|
||||
|
@ -177,6 +177,7 @@ export const CHAT_COMPLETION_SOURCES = {
|
||||
NANOGPT: 'nanogpt',
|
||||
DEEPSEEK: 'deepseek',
|
||||
XAI: 'xai',
|
||||
POLLINATIONS: 'pollinations',
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -57,6 +57,7 @@ const API_AI21 = 'https://api.ai21.com/studio/v1';
|
||||
const API_NANOGPT = 'https://nano-gpt.com/api/v1';
|
||||
const API_DEEPSEEK = 'https://api.deepseek.com/beta';
|
||||
const API_XAI = 'https://api.x.ai/v1';
|
||||
const API_POLLINATIONS = 'https://text.pollinations.ai/openai';
|
||||
|
||||
/**
|
||||
* Applies a post-processing step to the generated messages.
|
||||
@ -1010,6 +1011,10 @@ router.post('/status', async function (request, response_getstatus_openai) {
|
||||
api_url = new URL(request.body.reverse_proxy || API_XAI);
|
||||
api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
headers = {};
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) {
|
||||
api_url = 'https://text.pollinations.ai';
|
||||
api_key_openai = 'NONE';
|
||||
headers = {};
|
||||
} else {
|
||||
console.warn('This chat completion source is not supported yet.');
|
||||
return response_getstatus_openai.status(400).send({ error: true });
|
||||
@ -1031,7 +1036,12 @@ router.post('/status', async function (request, response_getstatus_openai) {
|
||||
|
||||
if (response.ok) {
|
||||
/** @type {any} */
|
||||
const data = await response.json();
|
||||
let data = await response.json();
|
||||
|
||||
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS && Array.isArray(data)) {
|
||||
data = { data: data.map(model => ({ id: model.name, ...model })) };
|
||||
}
|
||||
|
||||
response_getstatus_openai.send(data);
|
||||
|
||||
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.COHERE && Array.isArray(data?.models)) {
|
||||
@ -1293,6 +1303,14 @@ router.post('/generate', function (request, response) {
|
||||
apiKey = readSecret(request.user.directories, SECRET_KEYS.ZEROONEAI);
|
||||
headers = {};
|
||||
bodyParams = {};
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.POLLINATIONS) {
|
||||
apiUrl = API_POLLINATIONS;
|
||||
apiKey = 'NONE';
|
||||
headers = {};
|
||||
bodyParams = {
|
||||
reasoning_effort: request.body.reasoning_effort,
|
||||
private: true,
|
||||
};
|
||||
} else {
|
||||
console.warn('This chat completion source is not supported yet.');
|
||||
return response.status(400).send({ error: true });
|
||||
|
@ -73,7 +73,7 @@ router.post('/caption-image', async (request, response) => {
|
||||
key = readSecret(request.user.directories, SECRET_KEYS.XAI);
|
||||
}
|
||||
|
||||
const noKeyTypes = ['custom', 'ooba', 'koboldcpp', 'vllm', 'llamacpp'];
|
||||
const noKeyTypes = ['custom', 'ooba', 'koboldcpp', 'vllm', 'llamacpp', 'pollinations'];
|
||||
if (!key && !request.body.reverse_proxy && !noKeyTypes.includes(request.body.api)) {
|
||||
console.warn('No key found for API', request.body.api);
|
||||
return response.sendStatus(400);
|
||||
@ -147,6 +147,10 @@ router.post('/caption-image', async (request, response) => {
|
||||
apiUrl = 'https://api.x.ai/v1/chat/completions';
|
||||
}
|
||||
|
||||
if (request.body.api === 'pollinations') {
|
||||
apiUrl = 'https://text.pollinations.ai/openai/chat/completions';
|
||||
}
|
||||
|
||||
if (request.body.api === 'ooba') {
|
||||
apiUrl = `${trimV1(request.body.server_url)}/v1/chat/completions`;
|
||||
const imgMessage = body.messages.pop();
|
||||
|
Reference in New Issue
Block a user