Merge branch 'staging' into smol-tag-improvements
This commit is contained in:
commit
d98d811cc1
|
@ -0,0 +1,33 @@
|
|||
name: Update i18n data
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions: # Job-level permissions configuration starts here
|
||||
contents: write # 'write' access to repository contents
|
||||
steps:
|
||||
- name: disable auto crlf
|
||||
uses: steve02081504/disable-autocrlf@v1
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
- name: Create local changes
|
||||
run: |
|
||||
aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/generate.py
|
||||
aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/requirements.txt
|
||||
pip install -r ./requirements.txt
|
||||
python ./generate.py "" --sort-keys
|
||||
rm -f ./generate.py ./requirements.txt
|
||||
- name: add all
|
||||
run: git add -A
|
||||
- name: push
|
||||
uses: actions-go/push@master
|
||||
with:
|
||||
author-email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
author-name: github-actions[bot]
|
||||
commit-message: 'i18n changes'
|
||||
remote: origin
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "sillytavern",
|
||||
"version": "1.12.0",
|
||||
"version": "1.12.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sillytavern",
|
||||
"version": "1.12.0",
|
||||
"version": "1.12.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
||||
},
|
||||
"version": "1.12.0",
|
||||
"version": "1.12.1",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start:no-csrf": "node server.js --disableCsrf",
|
||||
|
|
|
@ -592,3 +592,23 @@ textarea:disabled {
|
|||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
ul.li-padding-b-1 li {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
ul.li-padding-b-2 li {
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
ul.li-padding-b-5 li {
|
||||
padding-bottom: 5em;
|
||||
}
|
||||
|
||||
ul.li-padding-bot5 li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.li-padding-bot10 li {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
|
|
@ -1230,6 +1230,11 @@
|
|||
<input class="neo-range-slider" type="range" id="rep_pen_range_textgenerationwebui" name="volume" min="-1" max="8192" step="1">
|
||||
<input class="neo-range-input" type="number" min="-1" max="8192" step="1" data-for="rep_pen_range_textgenerationwebui" id="rep_pen_range_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="koboldcpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small data-i18n="Rep. Pen. Slope">Rep Pen Slope</small>
|
||||
<input class="neo-range-slider" type="range" id="rep_pen_slope_textgenerationwebui" name="volume" min="0" max="10" step="0.01">
|
||||
<input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="rep_pen_slope_textgenerationwebui" id="rep_pen_slope_counter_textgenerationwebui">
|
||||
</div>
|
||||
<div data-tg-type="tabby" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
|
||||
<small data-i18n="rep.pen decay">Rep Pen Decay</small>
|
||||
<input class="neo-range-slider" type="range" id="rep_pen_decay_textgenerationwebui" name="volume" min="-1" max="8192" step="1">
|
||||
|
@ -2764,6 +2769,7 @@
|
|||
<option value="mistral-small-latest">mistral-small-latest</option>
|
||||
<option value="mistral-medium-latest">mistral-medium-latest</option>
|
||||
<option value="mistral-large-latest">mistral-large-latest</option>
|
||||
<option value="codestral-latest">codestral-latest</option>
|
||||
</optgroup>
|
||||
<optgroup label="Sub-versions">
|
||||
<option value="open-mixtral-8x22b-2404">open-mixtral-8x22b-2404</option>
|
||||
|
@ -2772,6 +2778,7 @@
|
|||
<option value="mistral-small-2402">mistral-small-2402</option>
|
||||
<option value="mistral-medium-2312">mistral-medium-2312</option>
|
||||
<option value="mistral-large-2402">mistral-large-2402</option>
|
||||
<option value="codestral-2405">codestral-2405</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -2817,10 +2824,8 @@
|
|||
<optgroup label="Open-Source Models">
|
||||
<option value="llama-3-8b-instruct">llama-3-8b-instruct</option>
|
||||
<option value="llama-3-70b-instruct">llama-3-70b-instruct</option>
|
||||
<option value="codellama-70b-instruct">codellama-70b-instruct</option>
|
||||
<option value="mistral-7b-instruct">mistral-7b-instruct (v0.2)</option>
|
||||
<option value="mixtral-8x7b-instruct">mixtral-8x7b-instruct</option>
|
||||
<option value="mixtral-8x22b-instruct">mixtral-8x22b-instruct</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1383,6 +1383,7 @@
|
|||
"Warning:": "警告:",
|
||||
"This action is irreversible.": "此操作不可逆。",
|
||||
"Type the user's handle below to confirm:": "在下面输入用户的名称以确认:",
|
||||
"Import Characters": "导入角色",
|
||||
"Enter the URL of the content to import": "输入要导入的内容的URL",
|
||||
"Supported sources:": "支持的来源:",
|
||||
"char_import_1": "Chub 角色(直链或ID)",
|
||||
|
@ -1394,6 +1395,8 @@
|
|||
"char_import_6": "被允许的PNG直链(请参阅",
|
||||
"char_import_7": ")",
|
||||
"char_import_8": "RisuRealm 角色(直链)",
|
||||
"Supports importing multiple characters.": "支持导入多个角色。",
|
||||
"Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。",
|
||||
"Export for character": "导出角色",
|
||||
"Export prompts for this character, including their order.": "导出此角色的提示,包括其顺序。",
|
||||
"Export all": "全部导出",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
207
public/script.js
207
public/script.js
|
@ -433,10 +433,12 @@ export const event_types = {
|
|||
CHAT_DELETED: 'chat_deleted',
|
||||
GROUP_CHAT_DELETED: 'group_chat_deleted',
|
||||
GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts',
|
||||
GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts',
|
||||
GROUP_MEMBER_DRAFTED: 'group_member_drafted',
|
||||
WORLD_INFO_ACTIVATED: 'world_info_activated',
|
||||
TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready',
|
||||
CHAT_COMPLETION_SETTINGS_READY: 'chat_completion_settings_ready',
|
||||
CHAT_COMPLETION_PROMPT_READY: 'chat_completion_prompt_ready',
|
||||
CHARACTER_FIRST_MESSAGE_SELECTED: 'character_first_message_selected',
|
||||
// TODO: Naming convention is inconsistent with other events
|
||||
CHARACTER_DELETED: 'characterDeleted',
|
||||
|
@ -4014,6 +4016,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||
|
||||
let finalPrompt = getCombinedPrompt(false);
|
||||
|
||||
const eventData = { prompt: finalPrompt, dryRun: dryRun };
|
||||
await eventSource.emit(event_types.GENERATE_AFTER_COMBINE_PROMPTS, eventData);
|
||||
finalPrompt = eventData.prompt;
|
||||
|
||||
let maxLength = Number(amount_gen); // how many tokens the AI will be requested to generate
|
||||
let thisPromptBits = [];
|
||||
|
||||
|
@ -5455,70 +5461,95 @@ export function setSendButtonState(value) {
|
|||
is_send_press = value;
|
||||
}
|
||||
|
||||
async function renameCharacter() {
|
||||
export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) {
|
||||
if (!name && silent) {
|
||||
toastr.warning('No character name provided.', 'Rename Character');
|
||||
return false;
|
||||
}
|
||||
if (this_chid === undefined) {
|
||||
toastr.warning('No character selected.', 'Rename Character');
|
||||
return false;
|
||||
}
|
||||
|
||||
const oldAvatar = characters[this_chid].avatar;
|
||||
const newValue = await callGenericPopup('<h3>New name:</h3>', POPUP_TYPE.INPUT, characters[this_chid].name);
|
||||
const newValue = name || await callGenericPopup('<h3>New name:</h3>', POPUP_TYPE.INPUT, characters[this_chid].name);
|
||||
|
||||
if (newValue && newValue !== characters[this_chid].name) {
|
||||
const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue });
|
||||
const response = await fetch('/api/characters/rename', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body,
|
||||
});
|
||||
if (!newValue) {
|
||||
toastr.warning('No character name provided.', 'Rename Character');
|
||||
return false;
|
||||
}
|
||||
if (newValue === characters[this_chid].name) {
|
||||
toastr.info('Same character name provided, so name did not change.', 'Rename Character');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const newAvatar = data.avatar;
|
||||
const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue });
|
||||
const response = await fetch('/api/characters/rename', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body,
|
||||
});
|
||||
|
||||
// Replace tags list
|
||||
renameTagKey(oldAvatar, newAvatar);
|
||||
try {
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const newAvatar = data.avatar;
|
||||
|
||||
// Reload characters list
|
||||
await getCharacters();
|
||||
// Replace tags list
|
||||
renameTagKey(oldAvatar, newAvatar);
|
||||
|
||||
// Find newly renamed character
|
||||
const newChId = characters.findIndex(c => c.avatar == data.avatar);
|
||||
// Reload characters list
|
||||
await getCharacters();
|
||||
|
||||
if (newChId !== -1) {
|
||||
// Select the character after the renaming
|
||||
this_chid = -1;
|
||||
await selectCharacterById(String(newChId));
|
||||
// Find newly renamed character
|
||||
const newChId = characters.findIndex(c => c.avatar == data.avatar);
|
||||
|
||||
// Async delay to update UI
|
||||
await delay(1);
|
||||
if (newChId !== -1) {
|
||||
// Select the character after the renaming
|
||||
this_chid = -1;
|
||||
await selectCharacterById(String(newChId));
|
||||
|
||||
if (this_chid === -1) {
|
||||
throw new Error('New character not selected');
|
||||
}
|
||||
// Async delay to update UI
|
||||
await delay(1);
|
||||
|
||||
// Also rename as a group member
|
||||
await renameGroupMember(oldAvatar, newAvatar, newValue);
|
||||
const renamePastChatsConfirm = await callPopup(`<h3>Character renamed!</h3>
|
||||
<p>Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?</p>
|
||||
<i><b>Sprites folder (if any) should be renamed manually.</b></i>`, 'confirm');
|
||||
|
||||
if (renamePastChatsConfirm) {
|
||||
await renamePastChats(newAvatar, newValue);
|
||||
await reloadCurrentChat();
|
||||
toastr.success('Character renamed and past chats updated!');
|
||||
}
|
||||
if (this_chid === -1) {
|
||||
throw new Error('New character not selected');
|
||||
}
|
||||
else {
|
||||
throw new Error('Newly renamed character was lost?');
|
||||
|
||||
// Also rename as a group member
|
||||
await renameGroupMember(oldAvatar, newAvatar, newValue);
|
||||
const renamePastChatsConfirm = renameChats !== null ? renameChats
|
||||
: silent ? false : await callPopup(`<h3>Character renamed!</h3>
|
||||
<p>Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?</p>
|
||||
<i><b>Sprites folder (if any) should be renamed manually.</b></i>`, 'confirm');
|
||||
|
||||
if (renamePastChatsConfirm) {
|
||||
await renamePastChats(newAvatar, newValue);
|
||||
await reloadCurrentChat();
|
||||
toastr.success('Character renamed and past chats updated!', 'Rename Character');
|
||||
} else {
|
||||
toastr.success('Character renamed!', 'Rename Character');
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error('Could not rename the character');
|
||||
throw new Error('Newly renamed character was lost?');
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// Reloading to prevent data corruption
|
||||
await callPopup('Something went wrong. The page will be reloaded.', 'text');
|
||||
location.reload();
|
||||
else {
|
||||
throw new Error('Could not rename the character');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// Reloading to prevent data corruption
|
||||
if (!silent) await callPopup('Something went wrong. The page will be reloaded.', 'text');
|
||||
else toastr.error('Something went wrong. The page will be reloaded.', 'Rename Character');
|
||||
|
||||
console.log('Renaming character error:', error);
|
||||
location.reload();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function renamePastChats(newAvatar, newValue) {
|
||||
|
@ -7678,6 +7709,8 @@ window['SillyTavern'].getContext = function () {
|
|||
setExtensionPrompt: setExtensionPrompt,
|
||||
updateChatMetadata: updateChatMetadata,
|
||||
saveChat: saveChatConditional,
|
||||
openCharacterChat: openCharacterChat,
|
||||
openGroupChat: openGroupChat,
|
||||
saveMetadata: saveMetadata,
|
||||
sendSystemMessage: sendSystemMessage,
|
||||
activateSendButtons,
|
||||
|
@ -10568,54 +10601,60 @@ jQuery(async function () {
|
|||
|
||||
$(document).on('click', '.external_import_button, #external_import_button', async () => {
|
||||
const html = await renderTemplateAsync('importCharacters');
|
||||
const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { okButton: $('#popup_template').attr('popup_text_import'), rows: 4 });
|
||||
|
||||
/** @type {string?} */
|
||||
const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { wider: true, okButton: $('#popup_template').attr('popup_text_import'), rows: 4 });
|
||||
|
||||
if (!input) {
|
||||
console.debug('Custom content import cancelled');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = input.trim();
|
||||
var request;
|
||||
// break input into one input per line
|
||||
const inputs = input.split('\n').map(x => x.trim()).filter(x => x.length > 0);
|
||||
|
||||
if (isValidUrl(url)) {
|
||||
console.debug('Custom content import started for URL: ', url);
|
||||
request = await fetch('/api/content/importURL', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ url }),
|
||||
});
|
||||
} else {
|
||||
console.debug('Custom content import started for Char UUID: ', url);
|
||||
request = await fetch('/api/content/importUUID', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ url }),
|
||||
});
|
||||
}
|
||||
for (const url of inputs) {
|
||||
let request;
|
||||
|
||||
if (!request.ok) {
|
||||
toastr.info(request.statusText, 'Custom content import failed');
|
||||
console.error('Custom content import failed', request.status, request.statusText);
|
||||
return;
|
||||
}
|
||||
if (isValidUrl(url)) {
|
||||
console.debug('Custom content import started for URL: ', url);
|
||||
request = await fetch('/api/content/importURL', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ url }),
|
||||
});
|
||||
} else {
|
||||
console.debug('Custom content import started for Char UUID: ', url);
|
||||
request = await fetch('/api/content/importUUID', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ url }),
|
||||
});
|
||||
}
|
||||
|
||||
const data = await request.blob();
|
||||
const customContentType = request.headers.get('X-Custom-Content-Type');
|
||||
const fileName = request.headers.get('Content-Disposition').split('filename=')[1].replace(/"/g, '');
|
||||
const file = new File([data], fileName, { type: data.type });
|
||||
if (!request.ok) {
|
||||
toastr.info(request.statusText, 'Custom content import failed');
|
||||
console.error('Custom content import failed', request.status, request.statusText);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (customContentType) {
|
||||
case 'character':
|
||||
await processDroppedFiles([file]);
|
||||
break;
|
||||
case 'lorebook':
|
||||
await importWorldInfo(file);
|
||||
break;
|
||||
default:
|
||||
toastr.warning('Unknown content type');
|
||||
console.error('Unknown content type', customContentType);
|
||||
break;
|
||||
const data = await request.blob();
|
||||
const customContentType = request.headers.get('X-Custom-Content-Type');
|
||||
const fileName = request.headers.get('Content-Disposition').split('filename=')[1].replace(/"/g, '');
|
||||
const file = new File([data], fileName, { type: data.type });
|
||||
|
||||
switch (customContentType) {
|
||||
case 'character':
|
||||
await processDroppedFiles([file]);
|
||||
break;
|
||||
case 'lorebook':
|
||||
await importWorldInfo(file);
|
||||
break;
|
||||
default:
|
||||
toastr.warning('Unknown content type');
|
||||
console.error('Unknown content type', customContentType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js';
|
||||
import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules } from '../../extensions.js';
|
||||
import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||
import { callPopup, getRequestHeaders, saveSettingsDebounced, substituteParams } from '../../../script.js';
|
||||
import { getMessageTimeStamp } from '../../RossAscends-mods.js';
|
||||
import { SECRET_KEYS, secret_state } from '../../secrets.js';
|
||||
|
@ -334,7 +334,7 @@ async function captionCommandCallback(args, prompt) {
|
|||
});
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
jQuery(async function () {
|
||||
function addSendPictureButton() {
|
||||
const sendButton = $(`
|
||||
<div id="send_picture" class="list-group-item flex-container flexGap5">
|
||||
|
@ -399,102 +399,12 @@ jQuery(function () {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
}
|
||||
function addSettings() {
|
||||
const html = `
|
||||
<div class="caption_settings">
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b>Image Captioning</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<label for="caption_source">Source</label>
|
||||
<select id="caption_source" class="text_pole">
|
||||
<option value="local">Local</option>
|
||||
<option value="multimodal">Multimodal (OpenAI / Anthropic / llama / Google)</option>
|
||||
<option value="extras">Extras</option>
|
||||
<option value="horde">Horde</option>
|
||||
</select>
|
||||
<div id="caption_multimodal_block" class="flex-container wide100p">
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_api">API</label>
|
||||
<select id="caption_multimodal_api" class="flex1 text_pole">
|
||||
<option value="anthropic">Anthropic</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
<option value="google">Google MakerSuite</option>
|
||||
<option value="koboldcpp">KoboldCpp</option>
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="ooba">Text Generation WebUI (oobabooga)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_model">Model</label>
|
||||
<select id="caption_multimodal_model" class="flex1 text_pole">
|
||||
<option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option>
|
||||
<option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option>
|
||||
<option data-type="openai" value="gpt-4o">gpt-4o</option>
|
||||
<option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option>
|
||||
<option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option>
|
||||
<option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
|
||||
<option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
|
||||
<option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4o">openai/gpt-4o</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-turbo">openai/gpt-4-turbo</option>
|
||||
<option data-type="openrouter" value="haotian-liu/llava-13b">haotian-liu/llava-13b</option>
|
||||
<option data-type="openrouter" value="fireworks/firellava-13b">fireworks/firellava-13b</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku">anthropic/claude-3-haiku</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet">anthropic/claude-3-sonnet</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus">anthropic/claude-3-opus</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku:beta">anthropic/claude-3-haiku:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet:beta">anthropic/claude-3-sonnet:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus:beta">anthropic/claude-3-opus:beta</option>
|
||||
<option data-type="openrouter" value="nousresearch/nous-hermes-2-vision-7b">nousresearch/nous-hermes-2-vision-7b</option>
|
||||
<option data-type="openrouter" value="google/gemini-pro-vision">google/gemini-pro-vision</option>
|
||||
<option data-type="openrouter" value="google/gemini-flash-1.5">google/gemini-flash-1.5</option>
|
||||
<option data-type="openrouter" value="liuhaotian/llava-yi-34b">liuhaotian/llava-yi-34b</option>
|
||||
<option data-type="ollama" value="ollama_current">[Currently selected]</option>
|
||||
<option data-type="ollama" value="bakllava:latest">bakllava:latest</option>
|
||||
<option data-type="ollama" value="llava:latest">llava:latest</option>
|
||||
<option data-type="llamacpp" value="llamacpp_current">[Currently loaded]</option>
|
||||
<option data-type="ooba" value="ooba_current">[Currently loaded]</option>
|
||||
<option data-type="koboldcpp" value="koboldcpp_current">[Currently loaded]</option>
|
||||
<option data-type="custom" value="custom_current">[Currently selected]</option>
|
||||
</select>
|
||||
</div>
|
||||
<label data-type="openai,anthropic,google" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid.">
|
||||
<input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox">
|
||||
Allow reverse proxy
|
||||
</label>
|
||||
<div class="flexBasis100p m-b-1">
|
||||
<small><b>Hint:</b> Set your API keys and endpoints in the 'API Connections' tab first.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="caption_prompt_block">
|
||||
<label for="caption_prompt">Caption Prompt</label>
|
||||
<textarea id="caption_prompt" class="text_pole" rows="1" placeholder="< Use default >">${PROMPT_DEFAULT}</textarea>
|
||||
<label class="checkbox_label margin-bot-10px" for="caption_prompt_ask" title="Ask for a custom prompt every time an image is captioned.">
|
||||
<input id="caption_prompt_ask" type="checkbox" class="checkbox">
|
||||
Ask every time
|
||||
</label>
|
||||
</div>
|
||||
<label for="caption_template">Message Template <small>(use <code>{{caption}}</code> macro)</small></label>
|
||||
<textarea id="caption_template" class="text_pole" rows="2" placeholder="< Use default >">${TEMPLATE_DEFAULT}</textarea>
|
||||
<label class="checkbox_label margin-bot-10px" for="caption_refine_mode">
|
||||
<input id="caption_refine_mode" type="checkbox" class="checkbox">
|
||||
Edit captions before saving
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
async function addSettings() {
|
||||
const html = await renderExtensionTemplateAsync('caption', 'settings');
|
||||
$('#extensions_settings2').append(html);
|
||||
}
|
||||
|
||||
addSettings();
|
||||
await addSettings();
|
||||
addPictureSendForm();
|
||||
addSendPictureButton();
|
||||
setImageIcon();
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
<div class="caption_settings">
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b>Image Captioning</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<label for="caption_source">Source</label>
|
||||
<select id="caption_source" class="text_pole">
|
||||
<option value="local">Local</option>
|
||||
<option value="multimodal">Multimodal (OpenAI / Anthropic / llama / Google)</option>
|
||||
<option value="extras">Extras</option>
|
||||
<option value="horde">Horde</option>
|
||||
</select>
|
||||
<div id="caption_multimodal_block" class="flex-container wide100p">
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_api">API</label>
|
||||
<select id="caption_multimodal_api" class="flex1 text_pole">
|
||||
<option value="anthropic">Anthropic</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
<option value="google">Google MakerSuite</option>
|
||||
<option value="koboldcpp">KoboldCpp</option>
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="ooba">Text Generation WebUI (oobabooga)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_model">Model</label>
|
||||
<select id="caption_multimodal_model" class="flex1 text_pole">
|
||||
<option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option>
|
||||
<option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option>
|
||||
<option data-type="openai" value="gpt-4o">gpt-4o</option>
|
||||
<option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option>
|
||||
<option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option>
|
||||
<option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
|
||||
<option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
|
||||
<option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4o">openai/gpt-4o</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-turbo">openai/gpt-4-turbo</option>
|
||||
<option data-type="openrouter" value="haotian-liu/llava-13b">haotian-liu/llava-13b</option>
|
||||
<option data-type="openrouter" value="fireworks/firellava-13b">fireworks/firellava-13b</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku">anthropic/claude-3-haiku</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet">anthropic/claude-3-sonnet</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus">anthropic/claude-3-opus</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku:beta">anthropic/claude-3-haiku:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet:beta">anthropic/claude-3-sonnet:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus:beta">anthropic/claude-3-opus:beta</option>
|
||||
<option data-type="openrouter" value="nousresearch/nous-hermes-2-vision-7b">nousresearch/nous-hermes-2-vision-7b</option>
|
||||
<option data-type="openrouter" value="google/gemini-pro-vision">google/gemini-pro-vision</option>
|
||||
<option data-type="openrouter" value="google/gemini-flash-1.5">google/gemini-flash-1.5</option>
|
||||
<option data-type="openrouter" value="liuhaotian/llava-yi-34b">liuhaotian/llava-yi-34b</option>
|
||||
<option data-type="ollama" value="ollama_current">[Currently selected]</option>
|
||||
<option data-type="ollama" value="bakllava:latest">bakllava:latest</option>
|
||||
<option data-type="ollama" value="llava:latest">llava:latest</option>
|
||||
<option data-type="llamacpp" value="llamacpp_current">[Currently loaded]</option>
|
||||
<option data-type="ooba" value="ooba_current">[Currently loaded]</option>
|
||||
<option data-type="koboldcpp" value="koboldcpp_current">[Currently loaded]</option>
|
||||
<option data-type="custom" value="custom_current">[Currently selected]</option>
|
||||
</select>
|
||||
</div>
|
||||
<label data-type="openai,anthropic,google" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid.">
|
||||
<input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox">
|
||||
Allow reverse proxy
|
||||
</label>
|
||||
<div class="flexBasis100p m-b-1">
|
||||
<small><b>Hint:</b> Set your API keys and endpoints in the 'API Connections' tab first.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="caption_prompt_block">
|
||||
<label for="caption_prompt">Caption Prompt</label>
|
||||
<textarea id="caption_prompt" class="text_pole" rows="1" placeholder="< Use default >">${PROMPT_DEFAULT}</textarea>
|
||||
<label class="checkbox_label margin-bot-10px" for="caption_prompt_ask" title="Ask for a custom prompt every time an image is captioned.">
|
||||
<input id="caption_prompt_ask" type="checkbox" class="checkbox">
|
||||
Ask every time
|
||||
</label>
|
||||
</div>
|
||||
<label for="caption_template">Message Template <small>(use <code>{{caption}}</code> macro)</small></label>
|
||||
<textarea id="caption_template" class="text_pole" rows="2" placeholder="< Use default >">${TEMPLATE_DEFAULT}</textarea>
|
||||
<label class="checkbox_label margin-bot-10px" for="caption_refine_mode">
|
||||
<input id="caption_refine_mode" type="checkbox" class="checkbox">
|
||||
Edit captions before saving
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -22,7 +22,7 @@ import {
|
|||
import { collapseNewlines } from '../../power-user.js';
|
||||
import { SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js';
|
||||
import { getDataBankAttachments, getDataBankAttachmentsForSource, getFileAttachment } from '../../chats.js';
|
||||
import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive } from '../../utils.js';
|
||||
import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive, trimToStartSentence, trimToEndSentence } from '../../utils.js';
|
||||
import { debounce_timeout } from '../../constants.js';
|
||||
import { getSortedEntries } from '../../world-info.js';
|
||||
import { textgen_types, textgenerationwebui_settings } from '../../textgen-settings.js';
|
||||
|
@ -66,11 +66,13 @@ const settings = {
|
|||
size_threshold: 10,
|
||||
chunk_size: 5000,
|
||||
chunk_count: 2,
|
||||
overlap_percent: 0,
|
||||
|
||||
// For Data Bank
|
||||
size_threshold_db: 5,
|
||||
chunk_size_db: 2500,
|
||||
chunk_count_db: 5,
|
||||
overlap_percent_db: 0,
|
||||
file_template_db: 'Related information:\n{{text}}',
|
||||
file_position_db: extension_prompt_types.IN_PROMPT,
|
||||
file_depth_db: 4,
|
||||
|
@ -369,7 +371,7 @@ async function processFiles(chat) {
|
|||
|
||||
// File is already in the collection
|
||||
if (!hashesInCollection.length) {
|
||||
await vectorizeFile(fileText, fileName, collectionId, settings.chunk_size);
|
||||
await vectorizeFile(fileText, fileName, collectionId, settings.chunk_size, settings.overlap_percent);
|
||||
}
|
||||
|
||||
const queryText = await getQueryText(chat);
|
||||
|
@ -409,7 +411,7 @@ async function ingestDataBankAttachments(source) {
|
|||
const thresholdLength = settings.size_threshold_db * 1024;
|
||||
// Use chunk size from settings if file is larger than threshold
|
||||
const chunkSize = file.size > thresholdLength ? settings.chunk_size_db : -1;
|
||||
await vectorizeFile(file.text, file.name, collectionId, chunkSize);
|
||||
await vectorizeFile(file.text, file.name, collectionId, chunkSize, settings.overlap_percent_db);
|
||||
}
|
||||
|
||||
return dataBankCollectionIds;
|
||||
|
@ -467,9 +469,10 @@ async function retrieveFileChunks(queryText, collectionId) {
|
|||
* @param {string} fileName File name
|
||||
* @param {string} collectionId File collection ID
|
||||
* @param {number} chunkSize Chunk size
|
||||
* @param {number} overlapPercent Overlap size (in %)
|
||||
* @returns {Promise<boolean>} True if successful, false if not
|
||||
*/
|
||||
async function vectorizeFile(fileText, fileName, collectionId, chunkSize) {
|
||||
async function vectorizeFile(fileText, fileName, collectionId, chunkSize, overlapPercent) {
|
||||
try {
|
||||
if (settings.translate_files && typeof window['translate'] === 'function') {
|
||||
console.log(`Vectors: Translating file ${fileName} to English...`);
|
||||
|
@ -478,8 +481,11 @@ async function vectorizeFile(fileText, fileName, collectionId, chunkSize) {
|
|||
}
|
||||
|
||||
const toast = toastr.info('Vectorization may take some time, please wait...', `Ingesting file ${fileName}`);
|
||||
const chunks = splitRecursive(fileText, chunkSize);
|
||||
console.debug(`Vectors: Split file ${fileName} into ${chunks.length} chunks`, chunks);
|
||||
const overlapSize = Math.round(chunkSize * overlapPercent / 100);
|
||||
// Overlap should not be included in chunk size. It will be later compensated by overlapChunks
|
||||
chunkSize = overlapSize > 0 ? (chunkSize - overlapSize) : chunkSize;
|
||||
const chunks = splitRecursive(fileText, chunkSize).map((x, y, z) => overlapSize > 0 ? overlapChunks(x, y, z, overlapSize) : x);
|
||||
console.debug(`Vectors: Split file ${fileName} into ${chunks.length} chunks with ${overlapPercent}% overlap`, chunks);
|
||||
|
||||
const items = chunks.map((chunk, index) => ({ hash: getStringHash(chunk), text: chunk, index: index }));
|
||||
await insertVectorItems(collectionId, items);
|
||||
|
@ -588,6 +594,26 @@ function getPromptText(queriedMessages) {
|
|||
return substituteParams(settings.template.replace(/{{text}}/i, queriedText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies text chunks to include overlap with adjacent chunks.
|
||||
* @param {string} chunk Current item
|
||||
* @param {number} index Current index
|
||||
* @param {string[]} chunks List of chunks
|
||||
* @param {number} overlapSize Size of the overlap
|
||||
* @returns {string} Overlapped chunks, with overlap trimmed to sentence boundaries
|
||||
*/
|
||||
function overlapChunks(chunk, index, chunks, overlapSize) {
|
||||
const halfOverlap = Math.floor(overlapSize / 2);
|
||||
const nextChunk = chunks[index + 1];
|
||||
const prevChunk = chunks[index - 1];
|
||||
|
||||
const nextOverlap = trimToEndSentence(nextChunk?.substring(0, halfOverlap)) || '';
|
||||
const prevOverlap = trimToStartSentence(prevChunk?.substring(prevChunk.length - halfOverlap)) || '';
|
||||
const overlappedChunk = [prevOverlap, chunk, nextOverlap].filter(x => x).join(' ');
|
||||
|
||||
return overlappedChunk;
|
||||
}
|
||||
|
||||
window['vectors_rearrangeChat'] = rearrangeChat;
|
||||
|
||||
const onChatEvent = debounce(async () => await moduleWorker.update(), debounce_timeout.relaxed);
|
||||
|
@ -969,8 +995,9 @@ async function onViewStatsClick() {
|
|||
toastr.info(`Total hashes: <b>${totalHashes}</b><br>
|
||||
Unique hashes: <b>${uniqueHashes}</b><br><br>
|
||||
I'll mark collected messages with a green circle.`,
|
||||
`Stats for chat ${chatId}`,
|
||||
{ timeOut: 10000, escapeHtml: false });
|
||||
`Stats for chat ${chatId}`,
|
||||
{ timeOut: 10000, escapeHtml: false },
|
||||
);
|
||||
|
||||
const chat = getContext().chat;
|
||||
for (const message of chat) {
|
||||
|
@ -1010,6 +1037,23 @@ async function onVectorizeAllFilesClick() {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the overlap percent for a file attachment.
|
||||
* @param file {import('../../chats.js').FileAttachment} File attachment
|
||||
* @returns {number} Overlap percent for the file
|
||||
*/
|
||||
function getOverlapPercent(file) {
|
||||
if (chatAttachments.includes(file)) {
|
||||
return settings.overlap_percent;
|
||||
}
|
||||
|
||||
if (dataBank.includes(file)) {
|
||||
return settings.overlap_percent_db;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
let allSuccess = true;
|
||||
|
||||
for (const file of allFiles) {
|
||||
|
@ -1023,7 +1067,8 @@ async function onVectorizeAllFilesClick() {
|
|||
}
|
||||
|
||||
const chunkSize = getChunkSize(file);
|
||||
const result = await vectorizeFile(text, file.name, collectionId, chunkSize);
|
||||
const overlapPercent = getOverlapPercent(file);
|
||||
const result = await vectorizeFile(text, file.name, collectionId, chunkSize, overlapPercent);
|
||||
|
||||
if (!result) {
|
||||
allSuccess = false;
|
||||
|
@ -1343,6 +1388,18 @@ jQuery(async () => {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#vectors_overlap_percent').val(settings.overlap_percent).on('input', () => {
|
||||
settings.overlap_percent = Number($('#vectors_overlap_percent').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#vectors_overlap_percent_db').val(settings.overlap_percent_db).on('input', () => {
|
||||
settings.overlap_percent_db = Number($('#vectors_overlap_percent_db').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#vectors_file_template_db').val(settings.file_template_db).on('input', () => {
|
||||
settings.file_template_db = String($('#vectors_file_template_db').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
|
|
|
@ -193,19 +193,25 @@
|
|||
<label for="vectors_size_threshold">
|
||||
<small>Size threshold (KB)</small>
|
||||
</label>
|
||||
<input id="vectors_size_threshold" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_size_threshold" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
<div class="flex1" title="Chunk size for file splitting.">
|
||||
<label for="vectors_chunk_size">
|
||||
<small>Chunk size (chars)</small>
|
||||
</label>
|
||||
<input id="vectors_chunk_size" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_chunk_size" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
<div class="flex1" title="The overlap between adjacent chunks in % from chunk size. The overlap text is trimmed to sentence boundaries. 0 = disabled.">
|
||||
<label for="vectors_overlap_percent">
|
||||
<small>Chunk overlap (%)</small>
|
||||
</label>
|
||||
<input id="vectors_overlap_percent" type="number" class="text_pole" min="0" max="99" step="1" />
|
||||
</div>
|
||||
<div class="flex1" title="How many chunks to retrieve when querying.">
|
||||
<label for="vectors_chunk_count">
|
||||
<small>Retrieve chunks</small>
|
||||
</label>
|
||||
<input id="vectors_chunk_count" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_chunk_count" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justifyCenter" title="These settings apply to files stored in the Data Bank.">
|
||||
|
@ -216,19 +222,25 @@
|
|||
<label for="vectors_size_threshold_db">
|
||||
<small>Size threshold (KB)</small>
|
||||
</label>
|
||||
<input id="vectors_size_threshold_db" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_size_threshold_db" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
<div class="flex1" title="Chunk size for file splitting.">
|
||||
<label for="vectors_chunk_size_db">
|
||||
<small>Chunk size (chars)</small>
|
||||
</label>
|
||||
<input id="vectors_chunk_size_db" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_chunk_size_db" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
<div class="flex1" title="The overlap between adjacent chunks in % from chunk size. The overlap text is trimmed to sentence boundaries. 0 = disabled.">
|
||||
<label for="vectors_overlap_percent_db">
|
||||
<small>Chunk overlap (%)</small>
|
||||
</label>
|
||||
<input id="vectors_overlap_percent_db" type="number" class="text_pole" min="0" max="99" step="1" />
|
||||
</div>
|
||||
<div class="flex1" title="How many chunks to retrieve when querying.">
|
||||
<label for="vectors_chunk_count_db">
|
||||
<small>Retrieve chunks</small>
|
||||
</label>
|
||||
<input id="vectors_chunk_count_db" type="number" class="text_pole widthUnset" min="1" max="99999" />
|
||||
<input id="vectors_chunk_count_db" type="number" class="text_pole" min="1" max="99999" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn">
|
||||
|
|
|
@ -1501,15 +1501,17 @@ async function onGroupActionClick(event) {
|
|||
const index = _thisGroup.disabled_members.indexOf(member.data('id'));
|
||||
if (index !== -1) {
|
||||
_thisGroup.disabled_members.splice(index, 1);
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
|
||||
if (action === 'disable') {
|
||||
member.addClass('disabled');
|
||||
const _thisGroup = groups.find(x => x.id === openGroupId);
|
||||
_thisGroup.disabled_members.push(member.data('id'));
|
||||
await editGroup(openGroupId, false, false);
|
||||
if (!_thisGroup.disabled_members.includes(member.data('id'))) {
|
||||
_thisGroup.disabled_members.push(member.data('id'));
|
||||
await editGroup(openGroupId, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (action === 'up' || action === 'down') {
|
||||
|
|
|
@ -1284,6 +1284,10 @@ export async function prepareOpenAIMessages({
|
|||
}
|
||||
|
||||
const chat = chatCompletion.getChat();
|
||||
|
||||
const eventData = { chat, dryRun };
|
||||
await eventSource.emit(event_types.CHAT_COMPLETION_PROMPT_READY, eventData);
|
||||
|
||||
openai_messages_count = chat.filter(x => x?.role === 'user' || x?.role === 'assistant')?.length || 0;
|
||||
|
||||
return [chat, promptManager.tokenHandler.counts];
|
||||
|
|
|
@ -771,6 +771,7 @@ async function CreateZenSliders(elmnt) {
|
|||
sliderID == 'max_temp_textgenerationwebui' ||
|
||||
sliderID == 'dynatemp_exponent_textgenerationwebui' ||
|
||||
sliderID == 'guidance_scale_textgenerationwebui' ||
|
||||
sliderID == 'rep_pen_slope_textgenerationwebui' ||
|
||||
sliderID == 'guidance_scale') {
|
||||
offVal = 1;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
name2,
|
||||
reloadCurrentChat,
|
||||
removeMacros,
|
||||
renameCharacter,
|
||||
saveChatConditional,
|
||||
sendMessageAsUser,
|
||||
sendSystemMessage,
|
||||
|
@ -323,6 +324,29 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||
helpString: 'Opens up a chat with the character or group by its name',
|
||||
aliases: ['char'],
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'rename-char',
|
||||
/** @param {{silent: string, chats: string}} options @param {string} name */
|
||||
callback: async ({ silent = 'true', chats = null }, name) => {
|
||||
const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null });
|
||||
return String(renamed);
|
||||
},
|
||||
returns: 'true/false - Whether the rename was successful',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'silent', 'Hide any blocking popups. (if false, the name is optional. If not supplied, a popup asking for it will appear)', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'chats', 'Rename char in all previous chats', [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'new char name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
],
|
||||
helpString: 'Renames the current character.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'sysgen',
|
||||
callback: generateSystemMessage,
|
||||
|
@ -336,15 +360,17 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'ask',
|
||||
callback: askCharacter,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'character name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandArgument(
|
||||
'prompt', [ARGUMENT_TYPE.STRING], true,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'name', 'character name', [ARGUMENT_TYPE.STRING], true, false, '',
|
||||
),
|
||||
],
|
||||
helpString: 'Asks a specified character card a prompt. Character name and prompt have to be separated by a new line.',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'prompt', [ARGUMENT_TYPE.STRING], true, false,
|
||||
),
|
||||
],
|
||||
helpString: 'Asks a specified character card a prompt. Character name must be provided in a named argument.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'delname',
|
||||
|
@ -1129,9 +1155,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||
helpString: 'Lists all script injections for the current chat.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'flushinjects',
|
||||
name: 'flushinject',
|
||||
aliases: ['flushinjects'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'injection ID or a variable name pointing to ID', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, false, '',
|
||||
),
|
||||
],
|
||||
callback: flushInjectsCallback,
|
||||
helpString: 'Removes all script injections for the current chat.',
|
||||
helpString: 'Removes a script injection for the current chat. If no ID is provided, removes all script injections.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'tokens',
|
||||
|
@ -1231,7 +1263,7 @@ function injectCallback(args, value) {
|
|||
}
|
||||
|
||||
function listInjectsCallback() {
|
||||
if (!chat_metadata.script_injects) {
|
||||
if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {
|
||||
toastr.info('No script injections for the current chat');
|
||||
return '';
|
||||
}
|
||||
|
@ -1251,17 +1283,29 @@ function listInjectsCallback() {
|
|||
sendSystemMessage(system_message_types.GENERIC, htmlMessage);
|
||||
}
|
||||
|
||||
function flushInjectsCallback() {
|
||||
/**
|
||||
* Flushes script injections for the current chat.
|
||||
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args Named arguments
|
||||
* @param {string} value Unnamed argument
|
||||
* @returns {string} Empty string
|
||||
*/
|
||||
function flushInjectsCallback(args, value) {
|
||||
if (!chat_metadata.script_injects) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const idArgument = resolveVariable(value, args._scope);
|
||||
|
||||
for (const [id, inject] of Object.entries(chat_metadata.script_injects)) {
|
||||
if (idArgument && id !== idArgument) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;
|
||||
setExtensionPrompt(prefixedId, '', inject.position, inject.depth, inject.scan, inject.role);
|
||||
delete chat_metadata.script_injects[id];
|
||||
}
|
||||
|
||||
chat_metadata.script_injects = {};
|
||||
saveMetadataDebounced();
|
||||
return '';
|
||||
}
|
||||
|
@ -1797,7 +1841,7 @@ async function deleteSwipeCallback(_, arg) {
|
|||
await reloadCurrentChat();
|
||||
}
|
||||
|
||||
async function askCharacter(_, text) {
|
||||
async function askCharacter(args, text) {
|
||||
// Prevent generate recursion
|
||||
$('#send_textarea').val('')[0].dispatchEvent(new Event('input', { bubbles: true }));
|
||||
|
||||
|
@ -1810,17 +1854,25 @@ async function askCharacter(_, text) {
|
|||
|
||||
if (!text) {
|
||||
console.warn('WARN: No text provided for /ask command');
|
||||
}
|
||||
|
||||
const parts = text.split('\n');
|
||||
if (parts.length <= 1) {
|
||||
toastr.warning('Both character name and message are required. Separate them with a new line.');
|
||||
toastr.warning('No text provided for /ask command');
|
||||
return;
|
||||
}
|
||||
|
||||
// Grabbing the message
|
||||
const name = parts.shift().trim();
|
||||
let mesText = parts.join('\n').trim();
|
||||
let name = '';
|
||||
let mesText = '';
|
||||
|
||||
if (args?.name) {
|
||||
name = args.name.trim();
|
||||
mesText = text.trim();
|
||||
|
||||
if (!name && !mesText) {
|
||||
toastr.warning('You must specify a name and text to ask.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mesText = getRegexedString(mesText, regex_placement.SLASH_COMMAND);
|
||||
|
||||
const prevChId = this_chid;
|
||||
|
||||
// Find the character
|
||||
|
@ -1831,7 +1883,7 @@ async function askCharacter(_, text) {
|
|||
}
|
||||
|
||||
// Override character and send a user message
|
||||
setCharacterId(chId);
|
||||
setCharacterId(String(chId));
|
||||
|
||||
// TODO: Maybe look up by filename instead of name
|
||||
const character = characters[chId];
|
||||
|
|
|
@ -17,6 +17,11 @@ import { SlashCommandScope } from './SlashCommandScope.js';
|
|||
* }} NamedArguments
|
||||
*/
|
||||
|
||||
/**
|
||||
* Alternative object for local JSDocs, where you don't need existing pipe, scope, etc. arguments
|
||||
* @typedef {{[id:string]:string|SlashCommandClosure}} NamedArgumentsCapture
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {string|SlashCommandClosure|(string|SlashCommandClosure)[]} UnnamedArguments
|
||||
*/
|
||||
|
@ -28,7 +33,7 @@ export class SlashCommand {
|
|||
* Creates a SlashCommand from a properties object.
|
||||
* @param {Object} props
|
||||
* @param {string} [props.name]
|
||||
* @param {(namedArguments:NamedArguments, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} [props.callback]
|
||||
* @param {(namedArguments:NamedArguments|NamedArgumentsCapture, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} [props.callback]
|
||||
* @param {string} [props.helpString]
|
||||
* @param {boolean} [props.splitUnnamedArgument]
|
||||
* @param {string[]} [props.aliases]
|
||||
|
|
|
@ -842,7 +842,7 @@ function newTag(tagName) {
|
|||
name: tagName,
|
||||
folder_type: TAG_FOLDER_DEFAULT_TYPE,
|
||||
filter_state: DEFAULT_FILTER_STATE,
|
||||
sort_order: tags.length,
|
||||
sort_order: Math.max(0, ...tags.map(t => t.sort_order)) + 1,
|
||||
color: '',
|
||||
color2: '',
|
||||
create_date: Date.now(),
|
||||
|
@ -1204,13 +1204,27 @@ function onGroupCreateClick() {
|
|||
}
|
||||
|
||||
export function applyTagsOnCharacterSelect(chid = null) {
|
||||
//clearTagsFilter();
|
||||
// If we are in create window, we cannot simply redraw, as there are no real persisted tags. Grab them, and pass them in
|
||||
if (menu_type === 'create') {
|
||||
const currentTagIds = $('#tagList').find('.tag').map((_, el) => $(el).attr('id')).get();
|
||||
const currentTags = tags.filter(x => currentTagIds.includes(x.id));
|
||||
printTagList($('#tagList'), { forEntityOrKey: null, tags: currentTags, tagOptions: { removable: true } });
|
||||
return;
|
||||
}
|
||||
|
||||
chid = chid ?? Number(this_chid);
|
||||
printTagList($('#tagList'), { forEntityOrKey: chid, tagOptions: { removable: true } });
|
||||
}
|
||||
|
||||
export function applyTagsOnGroupSelect(groupId = null) {
|
||||
//clearTagsFilter();
|
||||
// If we are in create window, we explicitly have to tell the system to print for the new group, not the one selected in the background
|
||||
if (menu_type === 'group_create') {
|
||||
const currentTagIds = $('#groupTagList').find('.tag').map((_, el) => $(el).attr('id')).get();
|
||||
const currentTags = tags.filter(x => currentTagIds.includes(x.id));
|
||||
printTagList($('#groupTagList'), { forEntityOrKey: null, tags: currentTags, tagOptions: { removable: true } });
|
||||
return;
|
||||
}
|
||||
|
||||
groupId = groupId ?? Number(selected_group);
|
||||
printTagList($('#groupTagList'), { forEntityOrKey: groupId, tagOptions: { removable: true } });
|
||||
}
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
<h3 data-i18n="Enter the URL of the content to import">Enter the URL of the content to import</h3>
|
||||
<span data-i18n="Supported sources:">Supported sources:</span><br>
|
||||
<ul class="justifyLeft">
|
||||
<li><span data-i18n="char_import_1">Chub Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>Anonymous/example-character</tt></li>
|
||||
<li><span data-i18n="char_import_2">Chub Lorebook (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>lorebooks/bartleby/example-lorebook</tt></li>
|
||||
<li><span data-i18n="char_import_3">JanitorAI Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li>
|
||||
<li><span data-i18n="char_import_4">Pygmalion.chat Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li>
|
||||
<li><span data-i18n="char_import_5">AICharacterCard.com Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>AICC/aicharcards/the-game-master</tt></li>
|
||||
<li><span data-i18n="char_import_6">Direct PNG Link (refer to</span> <code>config.yaml</code><span data-i18n="char_import_7"> for allowed hosts)</span><br><span data-i18n="char_import_example">Example:</span> <tt>https://files.catbox.moe/notarealfile.png</tt></li>
|
||||
<li><span data-i18n="char_import_8">RisuRealm Character (Direct Link)</span><br><span data-i18n="char_import_example">Example:</span> <tt>https://realm.risuai.net/character/3ca54c71-6efe-46a2-b9d0-4f62df23d712</tt></li>
|
||||
<ul>
|
||||
<h3 data-i18n="Import Characters">Import Characters</h3>
|
||||
<h4 data-i18n="Enter the URL of the content to import">Enter the URL of the content to import</h3>
|
||||
<div class="sources_list justifyLeft">
|
||||
<span data-i18n="Supported sources:">Supported sources:</span><br>
|
||||
<ul class="marginTop5 li-padding-bot5">
|
||||
<li><span data-i18n="char_import_1">Chub Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>Anonymous/example-character</tt></li>
|
||||
<li><span data-i18n="char_import_2">Chub Lorebook (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>lorebooks/bartleby/example-lorebook</tt></li>
|
||||
<li><span data-i18n="char_import_3">JanitorAI Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li>
|
||||
<li><span data-i18n="char_import_4">Pygmalion.chat Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li>
|
||||
<li><span data-i18n="char_import_5">AICharacterCard.com Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>AICC/aicharcards/the-game-master</tt></li>
|
||||
<li><span data-i18n="char_import_6">Direct PNG Link (refer to</span> <code>config.yaml</code><span data-i18n="char_import_7"> for allowed hosts)</span><br><span data-i18n="char_import_example">Example:</span> <tt>https://files.catbox.moe/notarealfile.png</tt></li>
|
||||
<li><span data-i18n="char_import_8">RisuRealm Character (Direct Link)</span><br><span data-i18n="char_import_example">Example:</span> <tt>https://realm.risuai.net/character/3ca54c71-6efe-46a2-b9d0-4f62df23d712</tt></li>
|
||||
</ul>
|
||||
</div>
|
||||
<small>
|
||||
<span data-i18n="Supports importing multiple characters.">
|
||||
Supports importing multiple characters.
|
||||
</span>
|
||||
<span data-i18n="Write each URL or ID into a new line.">
|
||||
Write each URL or ID into a new line.
|
||||
</span>
|
||||
</small>
|
||||
|
|
|
@ -101,6 +101,7 @@ const settings = {
|
|||
rep_pen: 1.2,
|
||||
rep_pen_range: 0,
|
||||
rep_pen_decay: 0,
|
||||
rep_pen_slope: 1,
|
||||
no_repeat_ngram_size: 0,
|
||||
penalty_alpha: 0,
|
||||
num_beams: 1,
|
||||
|
@ -180,6 +181,7 @@ export const setting_names = [
|
|||
'rep_pen',
|
||||
'rep_pen_range',
|
||||
'rep_pen_decay',
|
||||
'rep_pen_slope',
|
||||
'no_repeat_ngram_size',
|
||||
'top_k',
|
||||
'top_p',
|
||||
|
@ -1105,6 +1107,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
|||
'mirostat': settings.mirostat_mode,
|
||||
'ignore_eos': settings.ban_eos_token,
|
||||
'n_probs': power_user.request_token_probabilities ? 10 : undefined,
|
||||
'rep_pen_slope': settings.rep_pen_slope,
|
||||
};
|
||||
const vllmParams = {
|
||||
'n': canMultiSwipe ? settings.n : 1,
|
||||
|
|
|
@ -491,6 +491,10 @@ export function sortByCssOrder(a, b) {
|
|||
* trimToEndSentence('Hello, world! I am from'); // 'Hello, world!'
|
||||
*/
|
||||
export function trimToEndSentence(input, include_newline = false) {
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const punctuation = new Set(['.', '!', '?', '*', '"', ')', '}', '`', ']', '$', '。', '!', '?', '”', ')', '】', '’', '」', '_']); // extend this as you see fit
|
||||
let last = -1;
|
||||
|
||||
|
@ -520,6 +524,10 @@ export function trimToEndSentence(input, include_newline = false) {
|
|||
}
|
||||
|
||||
export function trimToStartSentence(input) {
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let p1 = input.indexOf('.');
|
||||
let p2 = input.indexOf('!');
|
||||
let p3 = input.indexOf('?');
|
||||
|
|
|
@ -456,6 +456,21 @@ code {
|
|||
color: var(--white70a);
|
||||
}
|
||||
|
||||
kbd {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
font-family: Consolas, monospace;
|
||||
white-space: nowrap;
|
||||
/* background-color: #eeeeee; */
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
color: #333;
|
||||
border: 1px solid #b4b4b4;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 2px 0 0 rgba(255, 255, 255, 0.7) inset;
|
||||
font-size: 90%;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
|
||||
hr {
|
||||
background-image: linear-gradient(90deg, var(--transparent), var(--SmartThemeBodyColor), var(--transparent));
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
const express = require('express');
|
||||
const fetch = require('node-fetch').default;
|
||||
const fs = require('fs');
|
||||
|
||||
const { jsonParser } = require('../../express-common');
|
||||
const { jsonParser, urlencodedParser } = require('../../express-common');
|
||||
const { forwardFetchResponse, delay } = require('../../util');
|
||||
const { getOverrideHeaders, setAdditionalHeaders } = require('../../additional-headers');
|
||||
const { getOverrideHeaders, setAdditionalHeaders, setAdditionalHeadersByType } = require('../../additional-headers');
|
||||
const { TEXTGEN_TYPES } = require('../../constants');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
@ -185,4 +187,55 @@ router.post('/status', jsonParser, async function (request, response) {
|
|||
response.send(result);
|
||||
});
|
||||
|
||||
router.post('/transcribe-audio', urlencodedParser, async function (request, response) {
|
||||
try {
|
||||
const server = request.body.server;
|
||||
|
||||
if (!server) {
|
||||
console.log('Server is not set');
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
if (!request.file) {
|
||||
console.log('No audio file found');
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
console.log('Transcribing audio with KoboldCpp', server);
|
||||
|
||||
const fileBase64 = fs.readFileSync(request.file.path).toString('base64');
|
||||
fs.rmSync(request.file.path);
|
||||
|
||||
const headers = {};
|
||||
setAdditionalHeadersByType(headers, TEXTGEN_TYPES.KOBOLDCPP, server, request.user.directories);
|
||||
|
||||
const url = new URL(server);
|
||||
url.pathname = '/api/extra/transcribe';
|
||||
|
||||
const result = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...headers,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prompt: '',
|
||||
audio_data: fileBase64,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
const text = await result.text();
|
||||
console.log('KoboldCpp request failed', result.statusText, text);
|
||||
return response.status(500).send(text);
|
||||
}
|
||||
|
||||
const data = await result.json();
|
||||
console.log('KoboldCpp transcription response', data);
|
||||
return response.json(data);
|
||||
} catch (error) {
|
||||
console.error('KoboldCpp transcription failed', error);
|
||||
response.status(500).send('Internal server error');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = { router };
|
||||
|
|
|
@ -956,6 +956,10 @@ router.post('/chats', jsonParser, async function (request, response) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (request.body.simple) {
|
||||
return response.send(jsonFiles.map(file => ({ file_name: file })));
|
||||
}
|
||||
|
||||
const jsonFilesPromise = jsonFiles.map((file) => {
|
||||
return new Promise(async (res) => {
|
||||
const pathToFile = path.join(request.user.directories.chats, characterDirectory, file);
|
||||
|
|
|
@ -77,7 +77,7 @@ router.post('/create', jsonParser, (request, response) => {
|
|||
generation_mode_join_suffix: request.body.generation_mode_join_suffix ?? '',
|
||||
};
|
||||
const pathToFile = path.join(request.user.directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(groupMetadata);
|
||||
const fileData = JSON.stringify(groupMetadata, null, 4);
|
||||
|
||||
if (!fs.existsSync(request.user.directories.groups)) {
|
||||
fs.mkdirSync(request.user.directories.groups);
|
||||
|
@ -93,7 +93,7 @@ router.post('/edit', jsonParser, (request, response) => {
|
|||
}
|
||||
const id = request.body.id;
|
||||
const pathToFile = path.join(request.user.directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(request.body);
|
||||
const fileData = JSON.stringify(request.body, null, 4);
|
||||
|
||||
writeFileAtomicSync(pathToFile, fileData);
|
||||
return response.send({ ok: true });
|
||||
|
|
|
@ -65,7 +65,7 @@ router.post('/text-workers', jsonParser, async (request, response) => {
|
|||
}
|
||||
|
||||
const agent = await getClientAgent();
|
||||
const fetchResult = await fetch('https://horde.koboldai.net/api/v2/workers?type=text', {
|
||||
const fetchResult = await fetch('https://aihorde.net/api/v2/workers?type=text', {
|
||||
headers: {
|
||||
'Client-Agent': agent,
|
||||
},
|
||||
|
@ -88,7 +88,7 @@ router.post('/text-models', jsonParser, async (request, response) => {
|
|||
}
|
||||
|
||||
const agent = await getClientAgent();
|
||||
const fetchResult = await fetch('https://horde.koboldai.net/api/v2/status/models?type=text', {
|
||||
const fetchResult = await fetch('https://aihorde.net/api/v2/status/models?type=text', {
|
||||
headers: {
|
||||
'Client-Agent': agent,
|
||||
},
|
||||
|
@ -106,7 +106,7 @@ router.post('/text-models', jsonParser, async (request, response) => {
|
|||
router.post('/status', jsonParser, async (_, response) => {
|
||||
try {
|
||||
const agent = await getClientAgent();
|
||||
const fetchResult = await fetch('https://horde.koboldai.net/api/v2/status/heartbeat', {
|
||||
const fetchResult = await fetch('https://aihorde.net/api/v2/status/heartbeat', {
|
||||
headers: {
|
||||
'Client-Agent': agent,
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ router.post('/cancel-task', jsonParser, async (request, response) => {
|
|||
try {
|
||||
const taskId = request.body.taskId;
|
||||
const agent = await getClientAgent();
|
||||
const fetchResult = await fetch(`https://horde.koboldai.net/api/v2/generate/text/status/${taskId}`, {
|
||||
const fetchResult = await fetch(`https://aihorde.net/api/v2/generate/text/status/${taskId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Client-Agent': agent,
|
||||
|
@ -143,7 +143,7 @@ router.post('/task-status', jsonParser, async (request, response) => {
|
|||
try {
|
||||
const taskId = request.body.taskId;
|
||||
const agent = await getClientAgent();
|
||||
const fetchResult = await fetch(`https://horde.koboldai.net/api/v2/generate/text/status/${taskId}`, {
|
||||
const fetchResult = await fetch(`https://aihorde.net/api/v2/generate/text/status/${taskId}`, {
|
||||
headers: {
|
||||
'Client-Agent': agent,
|
||||
},
|
||||
|
@ -160,7 +160,7 @@ router.post('/task-status', jsonParser, async (request, response) => {
|
|||
|
||||
router.post('/generate-text', jsonParser, async (request, response) => {
|
||||
const apiKey = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
|
||||
const url = 'https://horde.koboldai.net/api/v2/generate/text/async';
|
||||
const url = 'https://aihorde.net/api/v2/generate/text/async';
|
||||
const agent = await getClientAgent();
|
||||
|
||||
console.log(request.body);
|
||||
|
|
Loading…
Reference in New Issue