mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2d152d2705 | ||
|
f183f55c74 | ||
|
91f31e746e | ||
|
97716ea9ca | ||
|
6b669bbc22 | ||
|
18f84979f2 | ||
|
867c42cb6d | ||
|
d8d4732614 | ||
|
0f04508f30 | ||
|
530455979f | ||
|
f372b2ac16 | ||
|
03ad72b6c7 | ||
|
a49d0f1050 | ||
|
c557ade9b4 | ||
|
f5d5a75ef5 | ||
|
44a3bb8ec7 | ||
|
d7f86a7f6b | ||
|
90231680a9 | ||
|
dfc1719c3f | ||
|
80d9b08cc3 | ||
|
04372848c8 | ||
|
2dcb490e43 | ||
|
c1a5b50aae | ||
|
5183fb40a2 | ||
|
5d1f3b13ea | ||
|
b2eb361028 | ||
|
58c3d3eb7f | ||
|
c3129da879 | ||
|
b244a1c301 | ||
|
8ecab19966 | ||
|
2923d1454f | ||
|
f0cffb3dd9 | ||
|
b95cddec1c | ||
|
21fb143718 | ||
|
318235e13e | ||
|
2815990589 | ||
|
b158a86c25 | ||
|
f12aeeed90 | ||
|
41f53f4162 | ||
|
d192c5ae7f | ||
|
634c9aad3b | ||
|
ad48d6666a | ||
|
2a39db799a | ||
|
91c4de6605 | ||
|
5ad2a0d064 | ||
|
3b526ce207 | ||
|
169b1c2c63 | ||
|
9e8f3e0def | ||
|
eb634d597f | ||
|
24b315a149 | ||
|
83e264db9e | ||
|
08e3fc60c4 | ||
|
b7921f1edd |
37
.github/workflows/build-and-publish-release.yml
vendored
37
.github/workflows/build-and-publish-release.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Build and Publish Release (Release)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
|
||||
jobs:
|
||||
build_and_publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build and package with pkg
|
||||
run: |
|
||||
npm install -g pkg
|
||||
npm run pkg
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: dist/*
|
||||
tag_name: ci-release
|
||||
name: Continuous Release (Release)
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
37
.github/workflows/build-and-publish-staging.yml
vendored
37
.github/workflows/build-and-publish-staging.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Build and Publish Release (Staging)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- staging
|
||||
|
||||
jobs:
|
||||
build_and_publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build and package with pkg
|
||||
run: |
|
||||
npm install -g pkg
|
||||
npm run pkg
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: dist/*
|
||||
tag_name: ci-staging
|
||||
name: Continuous Release (Staging)
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
4
.github/workflows/docker-publish.yml
vendored
4
.github/workflows/docker-publish.yml
vendored
@@ -4,8 +4,8 @@ name: Create Docker Image on Release
|
||||
|
||||
on:
|
||||
release:
|
||||
# Only runs on full releases not pre releases
|
||||
types: [released]
|
||||
# Allow pre-releases
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
# This should allow creation of docker images even in forked repositories
|
||||
|
@@ -34,7 +34,8 @@ RUN \
|
||||
rm -f "config.yaml" "public/settings.json" || true && \
|
||||
ln -s "./config/config.yaml" "config.yaml" || true && \
|
||||
ln -s "../config/settings.json" "public/settings.json" || true && \
|
||||
mkdir "config" || true
|
||||
mkdir "config" || true && \
|
||||
mkdir -p "public/user" || true
|
||||
|
||||
# Cleanup unnecessary files
|
||||
RUN \
|
||||
|
1008
package-lock.json
generated
1008
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -55,11 +55,10 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
||||
},
|
||||
"version": "1.11.3",
|
||||
"version": "1.11.4",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start-multi": "node server.js --disableCsrf",
|
||||
"pkg": "pkg --compress Gzip --no-bytecode --public .",
|
||||
"postinstall": "node post-install.js",
|
||||
"lint": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js",
|
||||
"lint-fix": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js --fix"
|
||||
@@ -72,24 +71,8 @@
|
||||
"no-var": "off"
|
||||
},
|
||||
"main": "server.js",
|
||||
"pkg": {
|
||||
"targets": [
|
||||
"node18-linux-x64",
|
||||
"node18-macos-x64",
|
||||
"node18-windows-x64"
|
||||
],
|
||||
"assets": [
|
||||
"node_modules/**/*"
|
||||
],
|
||||
"outputPath": "dist",
|
||||
"scripts": [
|
||||
"server.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.55.0",
|
||||
"jquery": "^3.6.4",
|
||||
"pkg": "^5.8.1",
|
||||
"pkg-fetch": "^3.5.2"
|
||||
"jquery": "^3.6.4"
|
||||
}
|
||||
}
|
||||
|
@@ -1277,7 +1277,7 @@
|
||||
<div data-newbie-hidden data-tg-type="ooba, koboldcpp, aphrodite, tabby" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
|
||||
<small data-i18n="Smoothing Factor">Smoothing Factor</small>
|
||||
<input class="neo-range-slider" type="range" id="smoothing_factor_textgenerationwebui" name="volume" min="0" max="10" step="0.01" />
|
||||
<input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="smoothing_factor_textgenerationwebui" id="smoothing_factor_counter_textgenerationwebui">
|
||||
<input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="smoothing_factor_textgenerationwebui" id="smoothing_factor_counter_textgenerationwebui">
|
||||
</div>
|
||||
<!--
|
||||
<div data-tg-type="aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" data-i18n="Responses">
|
||||
@@ -1916,6 +1916,15 @@
|
||||
Make sure you run it with <code>--api</code> flag
|
||||
</span>
|
||||
</div>
|
||||
<h4 data-i18n="API key (optional)">API key (optional)</h4>
|
||||
<div class="flex-container">
|
||||
<input id="api_key_ooba" name="api_key_ooba" class="text_pole flex1 wide100p" maxlength="500" size="35" type="text" autocomplete="off">
|
||||
<div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_ooba">
|
||||
</div>
|
||||
</div>
|
||||
<div data-for="api_key_ooba" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<h4 data-i18n="Server url">Server URL</h4>
|
||||
<small data-i18n="Example: http://127.0.0.1:5000 ">Example: http://127.0.0.1:5000</small>
|
||||
|
@@ -2179,6 +2179,7 @@ function substituteParams(content, _name1, _name2, _original, _group, _replaceCh
|
||||
environment.user = _name1 ?? name1;
|
||||
environment.char = _name2 ?? name2;
|
||||
environment.group = environment.charIfNotGroup = _group ?? name2;
|
||||
environment.model = getGeneratingModel();
|
||||
|
||||
return evaluateMacros(content, environment);
|
||||
}
|
||||
@@ -5420,17 +5421,21 @@ export async function getUserAvatars(doRender = true, openPageAt = '') {
|
||||
if (response.ok) {
|
||||
const allEntities = await response.json();
|
||||
|
||||
if (!Array.isArray(allEntities)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
allEntities.sort((a, b) => {
|
||||
const aName = String(power_user.personas[a] || a);
|
||||
const bName = String(power_user.personas[b] || b);
|
||||
return power_user.persona_sort_order === 'asc' ? aName.localeCompare(bName) : bName.localeCompare(aName);
|
||||
});
|
||||
|
||||
if (!doRender) {
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
const entities = personasFilter.applyFilters(allEntities);
|
||||
entities.sort((a, b) => {
|
||||
const aName = String(power_user.personas[a]);
|
||||
const bName = String(power_user.personas[b]);
|
||||
return power_user.persona_sort_order === 'asc' ? aName.localeCompare(bName) : bName.localeCompare(aName);
|
||||
});
|
||||
|
||||
const storageKey = 'Personas_PerPage';
|
||||
const listId = '#user_avatar_block';
|
||||
const perPage = Number(localStorage.getItem(storageKey)) || 5;
|
||||
@@ -5490,6 +5495,7 @@ function highlightSelectedAvatar() {
|
||||
* @returns {JQuery<HTMLElement>} Avatar block
|
||||
*/
|
||||
function getUserAvatarBlock(name) {
|
||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
const template = $('#user_avatar_template .avatar-container').clone();
|
||||
const personaName = power_user.personas[name];
|
||||
const personaDescription = power_user.persona_descriptions[name]?.description;
|
||||
@@ -5498,7 +5504,11 @@ function getUserAvatarBlock(name) {
|
||||
template.attr('imgfile', name);
|
||||
template.find('.avatar').attr('imgfile', name).attr('title', name);
|
||||
template.toggleClass('default_persona', name === power_user.default_persona);
|
||||
template.find('img').attr('src', getUserAvatar(name));
|
||||
let avatarUrl = getUserAvatar(name);
|
||||
if (isFirefox) {
|
||||
avatarUrl += '?t=' + Date.now();
|
||||
}
|
||||
template.find('img').attr('src', avatarUrl);
|
||||
$('#user_avatar_block').append(template);
|
||||
return template;
|
||||
}
|
||||
@@ -6080,6 +6090,21 @@ export async function getPastCharacterChats(characterId = null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for `displayPastChats`, to make the same info consistently available for other functions
|
||||
*/
|
||||
function getCurrentChatDetails() {
|
||||
if (!characters[this_chid] && !selected_group) {
|
||||
return { sessionName: '', group: null, characterName: '', avatarImgURL: '' };
|
||||
}
|
||||
|
||||
const group = selected_group ? groups.find(x => x.id === selected_group) : null;
|
||||
const currentChat = selected_group ? group?.chat_id : characters[this_chid]['chat'];
|
||||
const displayName = selected_group ? group?.name : characters[this_chid].name;
|
||||
const avatarImg = selected_group ? group?.avatar_url : getThumbnailUrl('avatar', characters[this_chid]['avatar']);
|
||||
return { sessionName: currentChat, group: group, characterName: displayName, avatarImgURL: avatarImg };
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the past chats for a character or a group based on the selected context.
|
||||
* The function first fetches the chats, processes them, and then displays them in
|
||||
@@ -6090,7 +6115,6 @@ export async function displayPastChats() {
|
||||
$('#select_chat_div').empty();
|
||||
$('#select_chat_search').val('').off('input');
|
||||
|
||||
const group = selected_group ? groups.find(x => x.id === selected_group) : null;
|
||||
const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats());
|
||||
|
||||
if (!data) {
|
||||
@@ -6098,10 +6122,14 @@ export async function displayPastChats() {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentChat = selected_group ? group?.chat_id : characters[this_chid]['chat'];
|
||||
const displayName = selected_group ? group?.name : characters[this_chid].name;
|
||||
const avatarImg = selected_group ? group?.avatar_url : getThumbnailUrl('avatar', characters[this_chid]['avatar']);
|
||||
const chatDetails = getCurrentChatDetails();
|
||||
const group = chatDetails.group;
|
||||
const currentChat = chatDetails.sessionName;
|
||||
const displayName = chatDetails.characterName;
|
||||
const avatarImg = chatDetails.avatarImgURL;
|
||||
|
||||
const rawChats = await getChatsFromFiles(data, selected_group);
|
||||
|
||||
// Sort by last message date descending
|
||||
data.sort((a, b) => sortMoments(timestampToMoment(a.last_mes), timestampToMoment(b.last_mes)));
|
||||
console.log(data);
|
||||
@@ -7808,15 +7836,18 @@ async function doImpersonate() {
|
||||
}
|
||||
|
||||
async function doDeleteChat() {
|
||||
$('#option_select_chat').trigger('click', { fromSlashCommand: true });
|
||||
await delay(100);
|
||||
await displayPastChats();
|
||||
let currentChatDeleteButton = $('.select_chat_block[highlight=\'true\']').parent().find('.PastChat_cross');
|
||||
$(currentChatDeleteButton).trigger('click', { fromSlashCommand: true });
|
||||
$(currentChatDeleteButton).trigger('click');
|
||||
await delay(1);
|
||||
$('#dialogue_popup_ok').trigger('click');
|
||||
//200 delay needed let the past chat view reshow first
|
||||
await delay(200);
|
||||
$('#select_chat_cross').trigger('click');
|
||||
$('#dialogue_popup_ok').trigger('click', { fromSlashCommand: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* /getchatname` slash command
|
||||
*/
|
||||
async function doGetChatName() {
|
||||
return getCurrentChatDetails().sessionName;
|
||||
}
|
||||
|
||||
const isPwaMode = window.navigator.standalone;
|
||||
@@ -7970,6 +8001,7 @@ jQuery(async function () {
|
||||
registerSlashCommand('api', connectAPISlash, [], `<span class="monospace">(${Object.keys(CONNECT_API_MAP).join(', ')})</span> – connect to an API`, true, true);
|
||||
registerSlashCommand('impersonate', doImpersonate, ['imp'], '– calls an impersonation response', true, true);
|
||||
registerSlashCommand('delchat', doDeleteChat, [], '– deletes the current chat', true, true);
|
||||
registerSlashCommand('getchatname', doGetChatName, [], '– returns the name of the current chat file into the pipe', false, true);
|
||||
registerSlashCommand('closechat', doCloseChat, [], '– closes the current chat', true, true);
|
||||
registerSlashCommand('panels', doTogglePanels, ['togglepanels'], '– toggle UI panels on/off', true, true);
|
||||
registerSlashCommand('forcesave', doForceSave, [], '– forces a save of the current chat and settings', true, true);
|
||||
@@ -8199,7 +8231,8 @@ jQuery(async function () {
|
||||
$('#character_popup').css('display', 'none');
|
||||
});
|
||||
|
||||
$('#dialogue_popup_ok').click(async function (e) {
|
||||
$('#dialogue_popup_ok').click(async function (e, customData) {
|
||||
const fromSlashCommand = customData?.fromSlashCommand || false;
|
||||
dialogueCloseStop = false;
|
||||
$('#shadow_popup').transition({
|
||||
opacity: 0,
|
||||
@@ -8229,14 +8262,16 @@ jQuery(async function () {
|
||||
await delChat(chat_file_for_del);
|
||||
}
|
||||
|
||||
//open the history view again after 2seconds (delay to avoid edge cases for deleting last chat)
|
||||
//hide option popup menu
|
||||
setTimeout(function () {
|
||||
$('#option_select_chat').click();
|
||||
$('#options').hide();
|
||||
if (fromSlashCommand) { // When called from `/delchat` command, don't re-open the history view.
|
||||
$('#options').hide(); // hide option popup menu
|
||||
hideLoader();
|
||||
}, 2000);
|
||||
|
||||
} else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat).
|
||||
setTimeout(function () {
|
||||
$('#option_select_chat').click();
|
||||
$('#options').hide(); // hide option popup menu
|
||||
hideLoader();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
if (popup_type == 'del_ch') {
|
||||
const deleteChats = !!$('#del_char_checkbox').prop('checked');
|
||||
@@ -8532,6 +8567,11 @@ jQuery(async function () {
|
||||
await writeSecret(SECRET_KEYS.TOGETHERAI, togetherKey);
|
||||
}
|
||||
|
||||
const oobaKey = String($('#api_key_ooba').val()).trim();
|
||||
if (oobaKey.length) {
|
||||
await writeSecret(SECRET_KEYS.OOBA, oobaKey);
|
||||
}
|
||||
|
||||
validateTextGenUrl();
|
||||
startStatusLoading();
|
||||
main_api = 'textgenerationwebui';
|
||||
|
@@ -1132,7 +1132,7 @@ export function initRossMods() {
|
||||
.not('#right-nav-panel')
|
||||
.not('#floatingPrompt')
|
||||
.not('#cfgConfig')
|
||||
.not("#logprobsViewer")
|
||||
.not('#logprobsViewer')
|
||||
.is(':visible')) {
|
||||
let visibleDrawerContent = $('.drawer-content:visible')
|
||||
.not('#WorldInfo')
|
||||
@@ -1140,7 +1140,7 @@ export function initRossMods() {
|
||||
.not('#right-nav-panel')
|
||||
.not('#floatingPrompt')
|
||||
.not('#cfgConfig')
|
||||
.not("#logprobsViewer");
|
||||
.not('#logprobsViewer');
|
||||
$(visibleDrawerContent).parent().find('.drawer-icon').trigger('click');
|
||||
return;
|
||||
}
|
||||
|
@@ -58,6 +58,17 @@ function isTalkingHeadEnabled() {
|
||||
return extension_settings.expressions.talkinghead && !extension_settings.expressions.local;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Talkinghead mode on/off.
|
||||
*
|
||||
* Implements the `/th` slash command, which is meant to be bound to a Quick Reply button
|
||||
* as a quick way to switch Talkinghead on or off (e.g. to conserve GPU resources when AFK
|
||||
* for a long time).
|
||||
*/
|
||||
function toggleTalkingHeadCommand(_) {
|
||||
setTalkingHeadState(!extension_settings.expressions.talkinghead);
|
||||
}
|
||||
|
||||
function isVisualNovelMode() {
|
||||
return Boolean(!isMobile() && power_user.waifuMode && getContext().groupId);
|
||||
}
|
||||
@@ -389,13 +400,14 @@ function onExpressionsShowDefaultInput() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops animating a talkinghead.
|
||||
* Stops animating Talkinghead.
|
||||
*/
|
||||
async function unloadTalkingHead() {
|
||||
if (!modules.includes('talkinghead')) {
|
||||
console.debug('talkinghead module is disabled');
|
||||
return;
|
||||
}
|
||||
console.debug('expressions: Stopping Talkinghead');
|
||||
|
||||
try {
|
||||
const url = new URL(getApiUrl());
|
||||
@@ -418,6 +430,7 @@ async function loadTalkingHead() {
|
||||
console.debug('talkinghead module is disabled');
|
||||
return;
|
||||
}
|
||||
console.debug('expressions: Starting Talkinghead');
|
||||
|
||||
const spriteFolderName = getSpriteFolderName();
|
||||
|
||||
@@ -528,8 +541,7 @@ function handleImageChange() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTalkingHeadEnabled()) {
|
||||
// Method get IP of endpoint
|
||||
if (isTalkingHeadEnabled() && modules.includes('talkinghead')) {
|
||||
const talkingheadResultFeedSrc = `${getApiUrl()}/api/talkinghead/result_feed`;
|
||||
$('#expression-holder').css({ display: '' });
|
||||
if (imgElement.src !== talkingheadResultFeedSrc) {
|
||||
@@ -545,20 +557,26 @@ function handleImageChange() {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error); // Log the error if necessary
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
imgElement.src = ''; //remove incase char doesnt have expressions
|
||||
setExpression(getContext().name2, FALLBACK_EXPRESSION, true);
|
||||
imgElement.src = ''; // remove in case char doesn't have expressions
|
||||
|
||||
// When switching Talkinghead off, force-set the character to the last known expression, if any.
|
||||
// This preserves the same expression Talkinghead had at the moment it was switched off.
|
||||
const charName = getContext().name2;
|
||||
const last = lastExpression[charName];
|
||||
const targetExpression = last ? last : FALLBACK_EXPRESSION;
|
||||
setExpression(charName, targetExpression, true);
|
||||
}
|
||||
}
|
||||
|
||||
async function moduleWorker() {
|
||||
const context = getContext();
|
||||
|
||||
// Hide and disable talkinghead while in local mode
|
||||
// Hide and disable Talkinghead while in local mode
|
||||
$('#image_type_block').toggle(!extension_settings.expressions.local);
|
||||
|
||||
if (extension_settings.expressions.local && extension_settings.expressions.talkinghead) {
|
||||
@@ -691,7 +709,7 @@ async function moduleWorker() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts/stops talkinghead talking animation.
|
||||
* Starts/stops Talkinghead talking animation.
|
||||
*
|
||||
* Talking starts only when all the following conditions are met:
|
||||
* - The LLM is currently streaming its output.
|
||||
@@ -700,10 +718,13 @@ async function moduleWorker() {
|
||||
*
|
||||
* In all other cases, talking stops.
|
||||
*
|
||||
* A talkinghead API call is made only when the talking state changes.
|
||||
* A Talkinghead API call is made only when the talking state changes.
|
||||
*
|
||||
* Note that also the TTS system, if enabled, starts/stops the Talkinghead talking animation.
|
||||
* See `talkingAnimation` in `SillyTavern/public/scripts/extensions/tts/index.js`.
|
||||
*/
|
||||
async function updateTalkingState() {
|
||||
// Don't bother if talkinghead is disabled or not loaded.
|
||||
// Don't bother if Talkinghead is disabled or not loaded.
|
||||
if (!isTalkingHeadEnabled() || !modules.includes('talkinghead')) {
|
||||
return;
|
||||
}
|
||||
@@ -727,7 +748,7 @@ async function updateTalkingState() {
|
||||
newTalkingState = false;
|
||||
}
|
||||
try {
|
||||
// Call the talkinghead API only if the talking state changed.
|
||||
// Call the Talkinghead API only if the talking state changed.
|
||||
if (newTalkingState !== lastTalkingState) {
|
||||
console.debug(`updateTalkingState: calling ${url.pathname}`);
|
||||
await doExtrasFetch(url);
|
||||
@@ -787,6 +808,7 @@ function getSpriteFolderName(characterMessage = null, characterName = null) {
|
||||
}
|
||||
|
||||
function setTalkingHeadState(newState) {
|
||||
console.debug(`expressions: New talkinghead state: ${newState}`);
|
||||
extension_settings.expressions.talkinghead = newState; // Store setting
|
||||
saveSettingsDebounced();
|
||||
|
||||
@@ -871,12 +893,12 @@ async function setSpriteSlashCommand(_, spriteId) {
|
||||
|
||||
spriteId = spriteId.trim().toLowerCase();
|
||||
|
||||
// In talkinghead mode, don't check for the existence of the sprite
|
||||
// In Talkinghead mode, don't check for the existence of the sprite
|
||||
// (emotion names are the same as for sprites, but it only needs "talkinghead.png").
|
||||
const currentLastMessage = getLastCharacterMessage();
|
||||
const spriteFolderName = getSpriteFolderName(currentLastMessage, currentLastMessage.name);
|
||||
let label = spriteId;
|
||||
if (!isTalkingHeadEnabled()) {
|
||||
if (!isTalkingHeadEnabled() || !modules.includes('talkinghead')) {
|
||||
await validateImages(spriteFolderName);
|
||||
|
||||
// Fuzzy search for sprite
|
||||
@@ -1051,6 +1073,8 @@ function drawSpritesList(character, labels, sprites) {
|
||||
* @returns {string} Rendered list item template
|
||||
*/
|
||||
function getListItem(item, imageSrc, textClass, isCustom) {
|
||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
imageSrc = isFirefox ? `${imageSrc}?t=${Date.now()}` : imageSrc;
|
||||
return renderExtensionTemplate(MODULE_NAME, 'list-item', { item, imageSrc, textClass, isCustom });
|
||||
}
|
||||
|
||||
@@ -1144,7 +1168,7 @@ async function getExpressionsList() {
|
||||
}
|
||||
|
||||
async function setExpression(character, expression, force) {
|
||||
if (!isTalkingHeadEnabled()) {
|
||||
if (!isTalkingHeadEnabled() || !modules.includes('talkinghead')) {
|
||||
console.debug('entered setExpressions');
|
||||
await validateImages(character);
|
||||
const img = $('img.expression');
|
||||
@@ -1255,8 +1279,8 @@ async function setExpression(character, expression, force) {
|
||||
document.getElementById('expression-holder').style.display = '';
|
||||
|
||||
} else {
|
||||
// Set the talkinghead emotion to the specified expression
|
||||
// TODO: For now, talkinghead emote only supported when VN mode is off; see also updateVisualNovelMode.
|
||||
// Set the Talkinghead emotion to the specified expression
|
||||
// TODO: For now, Talkinghead emote only supported when VN mode is off; see also updateVisualNovelMode.
|
||||
try {
|
||||
let result = await isTalkingHeadAvailable();
|
||||
if (result) {
|
||||
@@ -1409,8 +1433,8 @@ async function onClickExpressionUpload(event) {
|
||||
// Reset the input
|
||||
e.target.form.reset();
|
||||
|
||||
// In talkinghead mode, when a new talkinghead image is uploaded, refresh the live char.
|
||||
if (isTalkingHeadEnabled() && id === 'talkinghead') {
|
||||
// In Talkinghead mode, when a new talkinghead image is uploaded, refresh the live char.
|
||||
if (id === 'talkinghead' && isTalkingHeadEnabled() && modules.includes('talkinghead')) {
|
||||
await loadTalkingHead();
|
||||
}
|
||||
};
|
||||
@@ -1520,6 +1544,11 @@ async function onClickExpressionUploadPackButton() {
|
||||
|
||||
// Reset the input
|
||||
e.target.form.reset();
|
||||
|
||||
// In Talkinghead mode, refresh the live char.
|
||||
if (isTalkingHeadEnabled() && modules.includes('talkinghead')) {
|
||||
await loadTalkingHead();
|
||||
}
|
||||
};
|
||||
|
||||
$('#expression_upload_pack')
|
||||
@@ -1657,6 +1686,34 @@ async function fetchImagesNoCache() {
|
||||
$('#expression_custom_remove').on('click', onClickExpressionRemoveCustom);
|
||||
}
|
||||
|
||||
// Pause Talkinghead to save resources when the ST tab is not visible or the window is minimized.
|
||||
// We currently do this via loading/unloading. Could be improved by adding new pause/unpause endpoints to Extras.
|
||||
document.addEventListener('visibilitychange', function (event) {
|
||||
let pageIsVisible;
|
||||
if (document.hidden) {
|
||||
console.debug('expressions: SillyTavern is now hidden');
|
||||
pageIsVisible = false;
|
||||
} else {
|
||||
console.debug('expressions: SillyTavern is now visible');
|
||||
pageIsVisible = true;
|
||||
}
|
||||
|
||||
if (isTalkingHeadEnabled() && modules.includes('talkinghead')) {
|
||||
isTalkingHeadAvailable().then(result => {
|
||||
if (result) {
|
||||
if (pageIsVisible) {
|
||||
loadTalkingHead();
|
||||
} else {
|
||||
unloadTalkingHead();
|
||||
}
|
||||
handleImageChange(); // Change image as needed
|
||||
} else {
|
||||
//console.log("talkinghead does not exist.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
addExpressionImage();
|
||||
addVisualNovelMode();
|
||||
addSettings();
|
||||
@@ -1664,7 +1721,7 @@ async function fetchImagesNoCache() {
|
||||
const updateFunction = wrapper.update.bind(wrapper);
|
||||
setInterval(updateFunction, UPDATE_INTERVAL);
|
||||
moduleWorker();
|
||||
// For setting the talkinghead talking animation on/off quickly enough for realtime use, we need another timer on a shorter schedule.
|
||||
// For setting the Talkinghead talking animation on/off quickly enough for realtime use, we need another timer on a shorter schedule.
|
||||
const wrapperTalkingState = new ModuleWorkerWrapper(updateTalkingState);
|
||||
const updateTalkingStateFunction = wrapperTalkingState.update.bind(wrapperTalkingState);
|
||||
setInterval(updateTalkingStateFunction, TALKINGCHECK_UPDATE_INTERVAL);
|
||||
@@ -1701,4 +1758,5 @@ async function fetchImagesNoCache() {
|
||||
registerSlashCommand('sprite', setSpriteSlashCommand, ['emote'], '<span class="monospace">(spriteId)</span> – force sets the sprite for the current character', true, true);
|
||||
registerSlashCommand('spriteoverride', setSpriteSetCommand, ['costume'], '<span class="monospace">(optional folder)</span> – sets an override sprite folder for the current character. If the name starts with a slash or a backslash, selects a sub-folder in the character-named folder. Empty value to reset to default.', true, true);
|
||||
registerSlashCommand('lastsprite', (_, value) => lastExpression[value.trim()] ?? '', [], '<span class="monospace">(charName)</span> – Returns the last set sprite / expression for the named character.', true, true);
|
||||
registerSlashCommand('th', toggleTalkingHeadCommand, ['talkinghead'], '– Character Expressions: toggles <i>Image Type - talkinghead (extras)</i> on/off.');
|
||||
})();
|
||||
|
@@ -73,12 +73,12 @@ function getRegexedString(rawString, placement, { characterOverride, isMarkdown,
|
||||
) {
|
||||
// Check if the depth is within the min/max depth
|
||||
if (typeof depth === 'number' && depth >= 0) {
|
||||
if (!isNaN(script.minDepth) && script.minDepth >= 0 && depth < script.minDepth) {
|
||||
if (!isNaN(script.minDepth) && script.minDepth !== null && script.minDepth >= 0 && depth < script.minDepth) {
|
||||
console.debug(`getRegexedString: Skipping script ${script.scriptName} because depth ${depth} is less than minDepth ${script.minDepth}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isNaN(script.maxDepth) && script.maxDepth >= 0 && depth > script.maxDepth) {
|
||||
if (!isNaN(script.maxDepth) && script.maxDepth !== null && script.maxDepth >= 0 && depth > script.maxDepth) {
|
||||
console.debug(`getRegexedString: Skipping script ${script.scriptName} because depth ${depth} is greater than maxDepth ${script.maxDepth}`);
|
||||
return;
|
||||
}
|
||||
|
@@ -536,7 +536,7 @@ async function processTtsQueue() {
|
||||
}
|
||||
|
||||
if (extension_settings.tts.narrate_quoted_only) {
|
||||
const special_quotes = /[“”]/g; // Extend this regex to include other special quotes
|
||||
const special_quotes = /[“”«»]/g; // Extend this regex to include other special quotes
|
||||
text = text.replace(special_quotes, '"');
|
||||
const matches = text.match(/".*?"/g); // Matches text inside double quotes, non-greedily
|
||||
const partJoiner = (ttsProvider?.separator || ' ... ');
|
||||
|
@@ -674,7 +674,7 @@ export function parseNovelAILogprobs(data) {
|
||||
// them with a logprob of -Infinity (0% probability)
|
||||
const notInAfter = befores
|
||||
.filter(([id]) => !afters.some(([aid]) => aid === id))
|
||||
.map(([id]) => [id, -Infinity])
|
||||
.map(([id]) => [id, -Infinity]);
|
||||
const merged = afters.concat(notInAfter);
|
||||
|
||||
// Add the chosen token to `merged` if it's not already there. This can
|
||||
|
@@ -31,6 +31,7 @@ import {
|
||||
this_chid,
|
||||
} from '../script.js';
|
||||
import { groups, selected_group } from './group-chats.js';
|
||||
import { registerSlashCommand } from './slash-commands.js';
|
||||
|
||||
import {
|
||||
chatCompletionDefaultPrompts,
|
||||
@@ -1617,7 +1618,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
}
|
||||
|
||||
// Add logprobs request (currently OpenAI only, max 5 on their side)
|
||||
if (useLogprobs && isOAI) {
|
||||
if (useLogprobs && (isOAI || isCustom)) {
|
||||
generate_data['logprobs'] = 5;
|
||||
}
|
||||
|
||||
@@ -1691,24 +1692,17 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
throw new Error(`Got response status ${response.status}`);
|
||||
}
|
||||
if (stream) {
|
||||
let reader;
|
||||
let isSSEStream = oai_settings.chat_completion_source !== chat_completion_sources.MAKERSUITE;
|
||||
if (isSSEStream) {
|
||||
const eventStream = new EventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
reader = eventStream.readable.getReader();
|
||||
} else {
|
||||
reader = response.body.getReader();
|
||||
}
|
||||
const eventStream = new EventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
const reader = eventStream.readable.getReader();
|
||||
return async function* streamData() {
|
||||
let text = '';
|
||||
let utf8Decoder = new TextDecoder();
|
||||
const swipes = [];
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) return;
|
||||
const rawData = isSSEStream ? value.data : utf8Decoder.decode(value, { stream: true });
|
||||
if (isSSEStream && rawData === '[DONE]') return;
|
||||
const rawData = value.data;
|
||||
if (rawData === '[DONE]') return;
|
||||
tryParseStreamingError(response, rawData);
|
||||
const parsed = JSON.parse(rawData);
|
||||
|
||||
@@ -1749,7 +1743,7 @@ function getStreamingReply(data) {
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.CLAUDE) {
|
||||
return data?.completion || '';
|
||||
} else if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) {
|
||||
return data?.candidates[0].content.parts[0].text || '';
|
||||
return data?.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
||||
} else {
|
||||
return data.choices[0]?.delta?.content || data.choices[0]?.message?.content || data.choices[0]?.text || '';
|
||||
}
|
||||
@@ -1768,6 +1762,7 @@ function parseChatCompletionLogprobs(data) {
|
||||
|
||||
switch (oai_settings.chat_completion_source) {
|
||||
case chat_completion_sources.OPENAI:
|
||||
case chat_completion_sources.CUSTOM:
|
||||
if (!data.choices?.length) {
|
||||
return null;
|
||||
}
|
||||
@@ -3933,6 +3928,28 @@ $('#delete_proxy').on('click', async function () {
|
||||
}
|
||||
});
|
||||
|
||||
function runProxyCallback(_, value) {
|
||||
if (!value) {
|
||||
toastr.warning('Proxy preset name is required');
|
||||
return '';
|
||||
}
|
||||
|
||||
const proxyNames = proxies.map(preset => preset.name);
|
||||
const fuse = new Fuse(proxyNames);
|
||||
const result = fuse.search(value);
|
||||
|
||||
if (result.length === 0) {
|
||||
toastr.warning(`Proxy preset "${value}" not found`);
|
||||
return '';
|
||||
}
|
||||
|
||||
const foundName = result[0].item;
|
||||
$('#openai_proxy_preset').val(foundName).trigger('change');
|
||||
return foundName;
|
||||
}
|
||||
|
||||
registerSlashCommand('proxy', runProxyCallback, [], '<span class="monospace">(name)</span> – sets a proxy preset by name');
|
||||
|
||||
$(document).ready(async function () {
|
||||
$('#test_api_button').on('click', testApiConnection);
|
||||
|
||||
|
@@ -17,6 +17,7 @@ export const SECRET_KEYS = {
|
||||
MISTRALAI: 'api_key_mistralai',
|
||||
TOGETHERAI: 'api_key_togetherai',
|
||||
CUSTOM: 'api_key_custom',
|
||||
OOBA: 'api_key_ooba',
|
||||
};
|
||||
|
||||
const INPUT_MAP = {
|
||||
@@ -35,6 +36,7 @@ const INPUT_MAP = {
|
||||
[SECRET_KEYS.MISTRALAI]: '#api_key_mistralai',
|
||||
[SECRET_KEYS.CUSTOM]: '#api_key_custom',
|
||||
[SECRET_KEYS.TOGETHERAI]: '#api_key_togetherai',
|
||||
[SECRET_KEYS.OOBA]: '#api_key_ooba',
|
||||
};
|
||||
|
||||
async function clearSecret() {
|
||||
|
@@ -154,7 +154,7 @@ parser.addCommand('sysgen', generateSystemMessage, [], '<span class="monospace">
|
||||
parser.addCommand('ask', askCharacter, [], '<span class="monospace">(prompt)</span> – asks a specified character card a prompt', true, true);
|
||||
parser.addCommand('delname', deleteMessagesByNameCallback, ['cancel'], '<span class="monospace">(name)</span> – deletes all messages attributed to a specified name', true, true);
|
||||
parser.addCommand('send', sendUserMessageCallback, [], '<span class="monospace">(text)</span> – adds a user message to the chat log without triggering a generation', true, true);
|
||||
parser.addCommand('trigger', triggerGenerationCallback, [], ' – triggers a message generation. If in group, can trigger a message for the specified group member index or name.', true, true);
|
||||
parser.addCommand('trigger', triggerGenerationCallback, [], ' <span class="monospace">await=true/false</span> – triggers a message generation. If in group, can trigger a message for the specified group member index or name. If <code>await=true</code> named argument passed, the command will await for the triggered generation before continuing.', true, true);
|
||||
parser.addCommand('hide', hideMessageCallback, [], '<span class="monospace">(message index or range)</span> – hides a chat message from the prompt', true, true);
|
||||
parser.addCommand('unhide', unhideMessageCallback, [], '<span class="monospace">(message index or range)</span> – unhides a message from the prompt', true, true);
|
||||
parser.addCommand('disable', disableGroupMemberCallback, [], '<span class="monospace">(member index or name)</span> – disables a group member from being drafted for replies', true, true);
|
||||
@@ -1029,8 +1029,9 @@ async function addGroupMemberCallback(_, arg) {
|
||||
return character.name;
|
||||
}
|
||||
|
||||
async function triggerGenerationCallback(_, arg) {
|
||||
setTimeout(async () => {
|
||||
async function triggerGenerationCallback(args, value) {
|
||||
const shouldAwait = isTrueBoolean(args?.await);
|
||||
const outerPromise = new Promise((outerResolve) => setTimeout(async () => {
|
||||
try {
|
||||
await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
|
||||
} catch {
|
||||
@@ -1044,16 +1045,21 @@ async function triggerGenerationCallback(_, arg) {
|
||||
|
||||
let chid = undefined;
|
||||
|
||||
if (selected_group && arg) {
|
||||
chid = findGroupMemberId(arg);
|
||||
if (selected_group && value) {
|
||||
chid = findGroupMemberId(value);
|
||||
|
||||
if (chid === undefined) {
|
||||
console.warn(`WARN: No group member found for argument ${arg}`);
|
||||
console.warn(`WARN: No group member found for argument ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => Generate('normal', { force_chid: chid }), 100);
|
||||
}, 1);
|
||||
outerResolve(new Promise(innerResolve => setTimeout(() => innerResolve(Generate('normal', { force_chid: chid })), 100)));
|
||||
}, 1));
|
||||
|
||||
if (shouldAwait) {
|
||||
const innerPromise = await outerPromise;
|
||||
await innerPromise;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
@@ -716,6 +716,7 @@ function parseTextgenLogprobs(token, logprobs) {
|
||||
}
|
||||
|
||||
switch (settings.type) {
|
||||
case TABBY:
|
||||
case APHRODITE:
|
||||
case OOBA: {
|
||||
/** @type {Record<string, number>[]} */
|
||||
@@ -807,6 +808,8 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
||||
'temperature': settings.dynatemp ? (settings.min_temp + settings.max_temp) / 2 : settings.temp,
|
||||
'top_p': settings.top_p,
|
||||
'typical_p': settings.typical_p,
|
||||
'typical': settings.typical_p,
|
||||
'sampler_seed': settings.seed,
|
||||
'min_p': settings.min_p,
|
||||
'repetition_penalty': settings.rep_pen,
|
||||
'frequency_penalty': settings.freq_pen,
|
||||
@@ -819,8 +822,8 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
||||
'early_stopping': settings.early_stopping,
|
||||
'add_bos_token': settings.add_bos_token,
|
||||
'dynamic_temperature': settings.dynatemp,
|
||||
'dynatemp_low': settings.dynatemp ? settings.min_temp : 0,
|
||||
'dynatemp_high': settings.dynatemp ? settings.max_temp : 0,
|
||||
'dynatemp_low': settings.dynatemp ? settings.min_temp : 1,
|
||||
'dynatemp_high': settings.dynatemp ? settings.max_temp : 1,
|
||||
'dynatemp_range': settings.dynatemp ? (settings.max_temp - settings.min_temp) / 2 : 0,
|
||||
'dynatemp_exponent': settings.dynatemp ? settings.dynatemp_exponent : 1,
|
||||
'smoothing_factor': settings.smoothing_factor,
|
||||
|
0
public/user/.gitkeep
Normal file
0
public/user/.gitkeep
Normal file
@@ -37,6 +37,14 @@ function getTabbyHeaders() {
|
||||
}) : {};
|
||||
}
|
||||
|
||||
function getOobaHeaders() {
|
||||
const apiKey = readSecret(SECRET_KEYS.OOBA);
|
||||
|
||||
return apiKey ? ({
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
}) : {};
|
||||
}
|
||||
|
||||
function getOverrideHeaders(urlHost) {
|
||||
const requestOverrides = getConfigValue('requestOverrides', []);
|
||||
const overrideHeaders = requestOverrides?.find((e) => e.hosts?.includes(urlHost))?.headers;
|
||||
@@ -69,6 +77,9 @@ function setAdditionalHeaders(request, args, server) {
|
||||
case TEXTGEN_TYPES.TOGETHERAI:
|
||||
headers = getTogetherAIHeaders();
|
||||
break;
|
||||
case TEXTGEN_TYPES.OOBA:
|
||||
headers = getOobaHeaders();
|
||||
break;
|
||||
default:
|
||||
headers = server ? getOverrideHeaders((new URL(server))?.host) : {};
|
||||
break;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const DIRECTORIES = {
|
||||
worlds: 'public/worlds/',
|
||||
user: 'public/user',
|
||||
avatars: 'public/User Avatars',
|
||||
images: 'public/img/',
|
||||
userImages: 'public/user/images/',
|
||||
|
@@ -267,7 +267,7 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
? (stream ? 'streamGenerateContent' : 'generateContent')
|
||||
: (isText ? 'generateText' : 'generateMessage');
|
||||
|
||||
const generateResponse = await fetch(`https://generativelanguage.googleapis.com/${apiVersion}/models/${model}:${responseType}?key=${apiKey}`, {
|
||||
const generateResponse = await fetch(`https://generativelanguage.googleapis.com/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`, {
|
||||
body: JSON.stringify(body),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -279,36 +279,8 @@ async function sendMakerSuiteRequest(request, response) {
|
||||
// have to do this because of their busted ass streaming endpoint
|
||||
if (stream) {
|
||||
try {
|
||||
let partialData = '';
|
||||
generateResponse.body.on('data', (data) => {
|
||||
const chunk = data.toString();
|
||||
if (chunk.startsWith(',') || chunk.endsWith(',') || chunk.startsWith('[') || chunk.endsWith(']')) {
|
||||
partialData = chunk.slice(1);
|
||||
} else {
|
||||
partialData += chunk;
|
||||
}
|
||||
while (true) {
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(partialData);
|
||||
} catch (e) {
|
||||
break;
|
||||
}
|
||||
response.write(JSON.stringify(json));
|
||||
partialData = '';
|
||||
}
|
||||
});
|
||||
|
||||
request.socket.on('close', function () {
|
||||
if (generateResponse.body instanceof Readable) generateResponse.body.destroy();
|
||||
response.end();
|
||||
});
|
||||
|
||||
generateResponse.body.on('end', () => {
|
||||
console.log('Streaming request finished');
|
||||
response.end();
|
||||
});
|
||||
|
||||
// Pipe remote SSE stream to Express response
|
||||
forwardFetchResponse(generateResponse, response);
|
||||
} catch (error) {
|
||||
console.log('Error forwarding streaming response:', error);
|
||||
if (!response.headersSent) {
|
||||
@@ -719,7 +691,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
// Adjust logprobs params for Chat Completions API, which expects { top_logprobs: number; logprobs: boolean; }
|
||||
if (!isTextCompletion && bodyParams.logprobs > 0) {
|
||||
bodyParams.top_logprobs = bodyParams.logprobs;
|
||||
bodyParams.logprobs = true
|
||||
bodyParams.logprobs = true;
|
||||
}
|
||||
|
||||
if (getConfigValue('openai.randomizeUserId', false)) {
|
||||
@@ -751,7 +723,16 @@ router.post('/generate', jsonParser, function (request, response) {
|
||||
apiUrl = request.body.custom_url;
|
||||
apiKey = readSecret(SECRET_KEYS.CUSTOM);
|
||||
headers = {};
|
||||
bodyParams = {};
|
||||
bodyParams = {
|
||||
logprobs: request.body.logprobs,
|
||||
};
|
||||
|
||||
// Adjust logprobs params for Chat Completions API, which expects { top_logprobs: number; logprobs: boolean; }
|
||||
if (!isTextCompletion && bodyParams.logprobs > 0) {
|
||||
bodyParams.top_logprobs = bodyParams.logprobs;
|
||||
bodyParams.logprobs = true;
|
||||
}
|
||||
|
||||
mergeObjectWithYaml(bodyParams, request.body.custom_include_body);
|
||||
mergeObjectWithYaml(headers, request.body.custom_include_headers);
|
||||
} else {
|
||||
|
@@ -216,7 +216,7 @@ router.post('/generate', jsonParser, async function (req, res) {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("NovelAI Output", data?.output);
|
||||
console.log('NovelAI Output', data?.output);
|
||||
return res.send(data);
|
||||
}
|
||||
} catch (error) {
|
||||
|
@@ -33,6 +33,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
||||
}
|
||||
|
||||
if (request.body.api === 'ooba') {
|
||||
key = readSecret(SECRET_KEYS.OOBA);
|
||||
bodyParams.temperature = 0.1;
|
||||
}
|
||||
|
||||
|
@@ -29,6 +29,7 @@ const SECRET_KEYS = {
|
||||
TOGETHERAI: 'api_key_togetherai',
|
||||
MISTRALAI: 'api_key_mistralai',
|
||||
CUSTOM: 'api_key_custom',
|
||||
OOBA: 'api_key_ooba',
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -172,7 +172,7 @@ function getSourceSettings(source, request) {
|
||||
|
||||
const sourceSettings = {
|
||||
extrasUrl: extrasUrl,
|
||||
extrasKey: extrasKey
|
||||
extrasKey: extrasKey,
|
||||
};
|
||||
return sourceSettings;
|
||||
}
|
||||
|
Reference in New Issue
Block a user