From 0480acebcd194f160944f6d082002f6df4282641 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Sun, 10 Sep 2023 04:08:15 +0300
Subject: [PATCH 1/4] #1059 Mancer model selector
---
public/css/select2-overrides.css | 29 ++++++++--
public/index.html | 12 ++--
public/lib/select2-search-placeholder.js | 25 ++++++++
public/script.js | 10 +++-
public/scripts/mancer-settings.js | 73 ++++++++++++++++++++++++
server.js | 27 ++++++++-
6 files changed, 162 insertions(+), 14 deletions(-)
create mode 100644 public/lib/select2-search-placeholder.js
create mode 100644 public/scripts/mancer-settings.js
diff --git a/public/css/select2-overrides.css b/public/css/select2-overrides.css
index 52918be45..1e394c035 100644
--- a/public/css/select2-overrides.css
+++ b/public/css/select2-overrides.css
@@ -19,11 +19,24 @@
color: var(--SmartThemeBodyColor);
}
+.select2-container .select2-search__field {
+ opacity: 0.8;
+}
+
+.select2-container .select2-selection--single .select2-selection__rendered {
+ color: var(--SmartThemeBodyColor);
+ line-height: revert;
+ padding-left: unset;
+}
+
+.select2-container .select2-results>.select2-results__options {
+ max-height: 300px;
+}
+
.select2-container .select2-selection--multiple .select2-selection__choice__remove {
padding: revert;
border-right: 1px solid var(--white30a);
font-size: 1.1em;
-
}
.select2-container .select2-selection--multiple .select2-selection__choice__display {
@@ -58,7 +71,8 @@
background-color: var(--SmartThemeBodyColor);
}
-.select2-container .select2-selection--multiple {
+.select2-container .select2-selection--multiple,
+.select2-container .select2-selection--single {
background-color: var(--black30a);
color: var(--SmartThemeBodyColor);
border: 1px solid var(--white30a);
@@ -67,11 +81,13 @@
padding: 3px 5px;
}
-.select2-container.select2-container--focus .select2-selection--multiple {
+.select2-container.select2-container--focus .select2-selection--multiple,
+.select2-container.select2-container--focus .select2-selection--single {
border: 1px solid var(--white30a);
}
-.select2-container .select2-selection--multiple .select2-selection__choice {
+.select2-container .select2-selection--multiple .select2-selection__choice,
+.select2-container .select2-selection--single .select2-selection__choice {
border-radius: 5px;
border-style: solid;
border-width: 1px;
@@ -119,7 +135,8 @@
border-radius: 2px;
}
-.select2-container .select2-selection--multiple .select2-selection__choice__remove {
+.select2-container .select2-selection--multiple .select2-selection__choice__remove,
+.select2-container .select2-selection--single .select2-selection__choice__remove {
color: var(--SmartThemeBodyColor);
}
@@ -131,4 +148,4 @@
background-color: var(--SmartThemeBlurTintColor);
text-align: center;
line-height: 14px;
-}
\ No newline at end of file
+}
diff --git a/public/index.html b/public/index.html
index 2ca5ebac5..26d9382ed 100644
--- a/public/index.html
+++ b/public/index.html
@@ -39,6 +39,7 @@
+
@@ -72,6 +73,7 @@
+
@@ -1849,19 +1851,21 @@
For privacy reasons, your API key will be hidden after you reload the page.
-
Blocking API url
+ Blocking API URL
Example: http://127.0.0.1:5000/api
-
Streaming API url
+ Streaming API URL
Example: ws://127.0.0.1:5005/api/v1/stream
diff --git a/public/lib/select2-search-placeholder.js b/public/lib/select2-search-placeholder.js
new file mode 100644
index 000000000..88ac6e397
--- /dev/null
+++ b/public/lib/select2-search-placeholder.js
@@ -0,0 +1,25 @@
+(function($) {
+
+ var Defaults = $.fn.select2.amd.require('select2/defaults');
+
+ $.extend(Defaults.defaults, {
+ searchInputPlaceholder: '',
+ searchInputCssClass: '',
+ });
+
+ var SearchDropdown = $.fn.select2.amd.require('select2/dropdown/search');
+
+ var _renderSearchDropdown = SearchDropdown.prototype.render;
+
+ SearchDropdown.prototype.render = function(decorated) {
+
+ // invoke parent method
+ var $rendered = _renderSearchDropdown.apply(this, Array.prototype.slice.apply(arguments));
+
+ this.$search.attr('placeholder', this.options.get('searchInputPlaceholder'));
+ this.$search.addClass(this.options.get('searchInputCssClass'));
+
+ return $rendered;
+ };
+
+})(window.jQuery);
diff --git a/public/script.js b/public/script.js
index ecc170884..cb65acdd9 100644
--- a/public/script.js
+++ b/public/script.js
@@ -177,6 +177,7 @@ import {
import { applyLocale } from "./scripts/i18n.js";
import { getTokenCount, getTokenizerModel, saveTokenCache } from "./scripts/tokenizers.js";
import { initPersonas, selectCurrentPersona, setPersonaDescription } from "./scripts/personas.js";
+import { loadMancerModels } from "./scripts/mancer-settings.js";
//exporting functions and vars for mods
export {
@@ -5037,10 +5038,9 @@ export function setGenerationParamsFromPreset(preset) {
}
if (preset.max_length !== undefined) {
- max_context = preset.max_length;
-
- const needsUnlock = max_context > MAX_CONTEXT_DEFAULT;
+ const needsUnlock = preset.max_length > MAX_CONTEXT_DEFAULT;
$('#max_context_unlocked').prop('checked', needsUnlock).trigger('change');
+ max_context = preset.max_length;
$("#max_context").val(max_context);
$("#max_context_counter").text(`${max_context}`);
@@ -7564,6 +7564,10 @@ jQuery(async function () {
api_use_mancer_webui = enabled;
saveSettingsDebounced();
getStatus();
+
+ if (enabled) {
+ loadMancerModels();
+ }
});
$("#api_button_textgenerationwebui").click(async function (e) {
diff --git a/public/scripts/mancer-settings.js b/public/scripts/mancer-settings.js
new file mode 100644
index 000000000..6bdb8a283
--- /dev/null
+++ b/public/scripts/mancer-settings.js
@@ -0,0 +1,73 @@
+import { api_server_textgenerationwebui, getRequestHeaders, setGenerationParamsFromPreset } from "../script.js";
+
+let models = [];
+
+/**
+ * @param {string} modelId
+ */
+export function getMancerModelURL(modelId) {
+ return `https://neuro.mancer.tech/webui/${modelId}/api`;
+}
+
+export async function loadMancerModels() {
+ try {
+ const response = await fetch('/api/mancer/models', {
+ method: 'POST',
+ headers: getRequestHeaders(),
+ });
+
+ if (!response.ok) {
+ return;
+ }
+
+ const data = await response.json();
+ models = data;
+
+ $('#mancer_model').empty();
+ for (const model of data) {
+ const option = document.createElement('option');
+ option.value = model.id;
+ option.text = model.name;
+ option.selected = api_server_textgenerationwebui === getMancerModelURL(model.id);
+ $('#mancer_model').append(option);
+ }
+
+ } catch {
+ console.warn('Failed to load Mancer models');
+ }
+}
+
+function onMancerModelSelect() {
+ const modelId = String($('#mancer_model').val());
+ const url = getMancerModelURL(modelId);
+ $('#mancer_api_url_text').val(url);
+ $('#api_button_textgenerationwebui').trigger('click');
+
+ const context = models.find(x => x.id === modelId)?.context;
+ setGenerationParamsFromPreset({ max_length: context });
+}
+
+function getMancerModelTemplate(option) {
+ const model = models.find(x => x.id === option?.element?.value);
+
+ if (!option.id || !model) {
+ return option.text;
+ }
+
+ return $((`
+
+
${DOMPurify.sanitize(model.name)} | ${model.context} ctx
+
${DOMPurify.sanitize(model.description)}
+
+ `));
+}
+
+jQuery(function () {
+ $('#mancer_model').on('change', onMancerModelSelect).select2({
+ placeholder: 'Select a model',
+ searchInputPlaceholder: 'Search models...',
+ searchInputCssClass: 'text_pole',
+ width: '100%',
+ templateResult: getMancerModelTemplate,
+ });
+});
diff --git a/server.js b/server.js
index 7e7a708b6..66885707a 100644
--- a/server.js
+++ b/server.js
@@ -810,6 +810,31 @@ app.post("/getchat", jsonParser, function (request, response) {
}
});
+app.post("/api/mancer/models", jsonParser, async function (_req, res) {
+ try {
+ const response = await fetch('https://mancer.tech/internal/api/models');
+ const data = await response.json();
+
+ if (!response.ok) {
+ console.log('Mancer models endpoint is offline.');
+ return res.json([]);
+ }
+
+ if (!Array.isArray(data.models)) {
+ console.log('Mancer models response is not an array.')
+ return res.json([]);
+ }
+
+ const modelIds = data.models.map(x => x.id);
+ console.log('Mancer models available:', modelIds);
+
+ return res.json(data.models);
+ } catch (error) {
+ console.error(error);
+ return res.json([]);
+ }
+});
+
// Only called for kobold and ooba/mancer
app.post("/getstatus", jsonParser, async function (request, response) {
if (!request.body) return response.sendStatus(400);
@@ -4331,7 +4356,7 @@ app.post('/generate_horde', jsonParser, async (request, response) => {
};
if (request.header('Client-Agent') !== undefined) args.headers['Client-Agent'] = request.header('Client-Agent');
- console.log(args.body);
+ console.log(request.body);
try {
const data = await postAsync(url, args);
return response.send(data);
From e2e32da4e6c65e5bc75a68c09c3333668272699b Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Sun, 10 Sep 2023 04:12:14 +0300
Subject: [PATCH 2/4] Unrestrict console logs display limit
---
server.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/server.js b/server.js
index 66885707a..126ab6e33 100644
--- a/server.js
+++ b/server.js
@@ -58,6 +58,10 @@ const { Tokenizer } = require('@agnai/web-tokenizers');
const _ = require('lodash');
const { generateRequestUrl, normaliseResponse } = require('google-translate-api-browser');
+// Unrestrict console logs display limit
+util.inspect.defaultOptions.maxArrayLength = null;
+util.inspect.defaultOptions.maxStringLength = null;
+
// Create files before running anything else
createDefaultFiles();
From d81c94de0b350cb35dbbd011b8c9020dd0b4dd42 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:30:29 +0300
Subject: [PATCH 3/4] Fix sort by date
---
public/scripts/power-user.js | 20 ++++++++++----------
server.js | 1 +
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js
index d6c27f546..4eb50f6b4 100644
--- a/public/scripts/power-user.js
+++ b/public/scripts/power-user.js
@@ -1153,15 +1153,15 @@ const compareFunc = (first, second) => {
return Math.random() > 0.5 ? 1 : -1;
}
+ const a = first[power_user.sort_field];
+ const b = second[power_user.sort_field];
+
+ if (power_user.sort_field === 'create_date') {
+ return sortMoments(timestampToMoment(b), timestampToMoment(a));
+ }
+
switch (power_user.sort_rule) {
case 'boolean':
- const a = first[power_user.sort_field];
- const b = second[power_user.sort_field];
-
- if (power_user.sort_field === 'create_date') {
- return sortMoments(timestampToMoment(a), timestampToMoment(b));
- }
-
if (a === true || a === 'true') return 1; // Prioritize 'true' or true
if (b === true || b === 'true') return -1; // Prioritize 'true' or true
if (a && !b) return -1; // Move truthy values to the end
@@ -1169,9 +1169,9 @@ const compareFunc = (first, second) => {
if (a === b) return 0; // Sort equal values normally
return a < b ? -1 : 1; // Sort non-boolean values normally
default:
- return typeof first[power_user.sort_field] == "string"
- ? first[power_user.sort_field].localeCompare(second[power_user.sort_field])
- : first[power_user.sort_field] - second[power_user.sort_field];
+ return typeof a == "string"
+ ? a.localeCompare(b)
+ : a - b;
}
};
diff --git a/server.js b/server.js
index 126ab6e33..2488f0fcc 100644
--- a/server.js
+++ b/server.js
@@ -2178,6 +2178,7 @@ app.post("/importcharacter", urlencodedParser, async function (request, response
importRisuSprites(jsonData);
unsetFavFlag(jsonData);
jsonData = readFromV2(jsonData);
+ jsonData["create_date"] = humanizedISO8601DateTime();
png_name = getPngName(jsonData.data?.name || jsonData.name);
let char = JSON.stringify(jsonData);
charaWrite(defaultAvatarPath, char, png_name, response, { file_name: png_name });
From dc5deaf47c583051059c0a7f3126a068bb020bec Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Sun, 10 Sep 2023 14:39:49 +0300
Subject: [PATCH 4/4] Mobile doesn't like select2
---
public/script.js | 1 +
public/scripts/mancer-settings.js | 20 +++++++++++++-------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/public/script.js b/public/script.js
index cb65acdd9..13c1d4b86 100644
--- a/public/script.js
+++ b/public/script.js
@@ -8473,6 +8473,7 @@ jQuery(async function () {
'.ui-widget',
'.text_pole',
'#toast-container',
+ '.select2-results',
];
for (const id of forbiddenTargets) {
if (clickTarget.closest(id).length > 0) {
diff --git a/public/scripts/mancer-settings.js b/public/scripts/mancer-settings.js
index 6bdb8a283..a6cfd9ca0 100644
--- a/public/scripts/mancer-settings.js
+++ b/public/scripts/mancer-settings.js
@@ -1,4 +1,5 @@
import { api_server_textgenerationwebui, getRequestHeaders, setGenerationParamsFromPreset } from "../script.js";
+import { getDeviceInfo } from "./RossAscends-mods.js";
let models = [];
@@ -63,11 +64,16 @@ function getMancerModelTemplate(option) {
}
jQuery(function () {
- $('#mancer_model').on('change', onMancerModelSelect).select2({
- placeholder: 'Select a model',
- searchInputPlaceholder: 'Search models...',
- searchInputCssClass: 'text_pole',
- width: '100%',
- templateResult: getMancerModelTemplate,
- });
+ $('#mancer_model').on('change', onMancerModelSelect);
+
+ const deviceInfo = getDeviceInfo();
+ if (deviceInfo && deviceInfo.device.type === 'desktop') {
+ $('#mancer_model').select2({
+ placeholder: 'Select a model',
+ searchInputPlaceholder: 'Search models...',
+ searchInputCssClass: 'text_pole',
+ width: '100%',
+ templateResult: getMancerModelTemplate,
+ });
+ }
});