Working state stat UI

This commit is contained in:
BlipRanger
2023-07-18 00:36:28 -04:00
parent b1f1fa8a26
commit b058f40ee6
7 changed files with 133 additions and 33 deletions

View File

@@ -2566,6 +2566,9 @@
<input type="file" id="avatar_upload_file" accept="image/*" name="avatar">
<input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value="">
</form>
<button class="menu_button user_stats_button" title="Click for stats!" style="position: absolute; right: 0; bottom: 0;">
<i class="fa-solid fa-circle-info"></i>
</button>
</div>
</div>
</div>
@@ -2604,7 +2607,6 @@
<div id="rm_button_selected_ch">
<h2></h2>
</div>
</div>
</div>
<!-- end group peeking cope structure-->

View File

@@ -1,4 +1,5 @@
import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, AA_CountCharTime } from "./scripts/RossAscends-mods.js";
import { humanizedDateTime, humanizeGenTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, AA_CountCharTime } from "./scripts/RossAscends-mods.js";
import { userStatsHandler, characterStatsHandler } from './scripts/stats.js';
import { encode } from "../scripts/gpt-2-3-tokenizer/mod.js";
import { GPT3BrowserTokenizer } from "../scripts/gpt-3-tokenizer/gpt3-tokenizer.js";
import {
@@ -955,7 +956,7 @@ async function getCharacters() {
updateCharacterCount('#rm_print_characters_block > div');
await AA_CountCharTime(this_chid);
//await AA_CountCharTime(this_chid);
}
}
@@ -4895,7 +4896,6 @@ async function getSettings(type) {
}
const data = await response.json();
getStats();
if (data.result != "file not find" && data.settings) {
settings = JSON.parse(data.settings);
if (settings.username !== undefined) {
@@ -5122,25 +5122,6 @@ async function saveSettings(type) {
}
async function getStats() {
const response = await fetch("/getstats", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({}),
cache: "no-cache",
});
if (!response.ok) {
toastr.error('Stats could not be loaded. Try reloading the page.');
throw new Error('Error getting stats');
}
const data = await response.json();
charStats = data;
console.log(charStats);
}
function setCharacterBlockHeight() {
const $children = $("#rm_print_characters_block").children();
@@ -8581,6 +8562,10 @@ $(document).ready(function () {
restoreCaretPosition($(this).get(0), caretPosition);
});
$(".user_stats_button").on('click', function () {
userStatsHandler(charStats);
});
$('#external_import_button').on('click', async () => {
const html = `<h3>Enter the URL of the content to import</h3>
Supported sources:<br>
@@ -8719,4 +8704,4 @@ $(document).ready(function () {
$("#charListGridToggle").on('click', async () => {
doCharListDisplaySwitch();
});
})
});

View File

@@ -16,6 +16,10 @@ import {
charStats,
} from "../script.js";
import {
characterStatsHandler,
} from "./stats.js";
import {
power_user,
@@ -72,7 +76,7 @@ const observer = new MutationObserver(function (mutations) {
RA_checkOnlineStatus();
} else if (mutation.target.parentNode === SelectedCharacterTab) {
setTimeout(RA_CountCharTokens, 200);
setTimeout(AA_CountCharTime, 200);
//setTimeout(AA_CountCharTime, 200);
}
});
});
@@ -108,10 +112,10 @@ function waitForElement(querySelector, timeout) {
//humanize character generation time
export function humanizeGenTime(character) {
let stat = charStats[character.avatar]
export function humanizeGenTime(total_gen_time) {
//convert time_spent to humanized format of "_ Hours, _ Minutes, _ Seconds" from milliseconds
let time_spent = stat.total_gen_time
let time_spent = total_gen_time || 0;
time_spent = Math.floor(time_spent / 1000);
let seconds = time_spent % 60;
time_spent = Math.floor(time_spent / 60);
@@ -327,7 +331,10 @@ export function RA_CountCharTokens() {
// if neither, probably safety char or some error in loading
} else { console.debug("RA_TC -- no valid char found, closing."); }
}
$("#result_info").html(`<small>${count_tokens} Tokens (${perm_tokens} Permanent)</small>`);
//label rm_stats_button with a tooltip indicating stats
$("#result_info").html(`<small>${count_tokens} Tokens (${perm_tokens} Permanent)</small>
<i title='Click for stats!' class="fa-solid fa-circle-info rm_stats_button"></i>`);
// display the counted tokens
const tokenLimit = Math.max(((main_api !== 'openai' ? max_context : oai_settings.openai_max_context) / 2), 1024);
if (count_tokens < tokenLimit && perm_tokens < tokenLimit) {
@@ -339,10 +346,16 @@ export function RA_CountCharTokens() {
<small class="flex-container flexnowrap flexNoGap">
<div class="neutral_warning">${count_tokens}</div>&nbsp;Tokens (<div class="neutral_warning">${perm_tokens}</div><div>&nbsp;Permanent)</div>
</small>
<i title='Click for stats!' class="fa-solid fa-circle-info rm_stats_button"></i>
</div>
<div id="chartokenwarning" class="menu_button margin0 whitespacenowrap"><a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-tokens" target="_blank">About Token 'Limits'</a></div>
</div>`);
} //warn if either are over 1024
$(".rm_stats_button").on('click', function () {
characterStatsHandler(charStats, characters, this_chid);
});
}
//Auto Load Last Charcter -- (fires when active_character is defined and auto_load_chat is true)
async function RA_autoloadchat() {

View File

@@ -1223,7 +1223,7 @@ function openCharacterDefinition(characterSelect) {
select_selected_character(chid);
// Gentle nudge to recalculate tokens
RA_CountCharTokens();
AA_CountCharTime(chid);
//AA_CountCharTime(chid);
// Do a little tomfoolery to spoof the tag selector
applyTagsOnCharacterSelect.call(characterSelect);
}

98
public/scripts/stats.js Normal file
View File

@@ -0,0 +1,98 @@
// statsHelper.js
import { getRequestHeaders, callPopup, token } from '../script.js';
import { humanizeGenTime } from './RossAscends-mods.js';
// Function for creating stat block HTML
function createStatBlock(statName, statValue) {
return `<div class="rm_stat_block">
<div class="rm_stat_name">${statName}:</div>
<div class="rm_stat_value">${statValue}</div>
</div>`;
}
function calculateTotal(stat) {
return isNaN(stat) ? 0 : stat;
}
function calculateTotalStats(charStats) {
let totalStats = {
total_gen_time: 0,
user_msg_count: 0,
non_user_msg_count: 0,
user_word_count: 0,
non_user_word_count: 0,
total_swipe_count: 0
};
for (let stats of Object.values(charStats)) {
totalStats.total_gen_time += calculateTotal(stats.total_gen_time);
totalStats.user_msg_count += calculateTotal(stats.user_msg_count);
totalStats.non_user_msg_count += calculateTotal(stats.non_user_msg_count);
totalStats.user_word_count += calculateTotal(stats.user_word_count);
totalStats.non_user_word_count += calculateTotal(stats.non_user_word_count);
totalStats.total_swipe_count += calculateTotal(stats.total_swipe_count);
}
return totalStats;
}
function createHtml(statsType, stats) {
// Get time string
let timeStirng = humanizeGenTime(stats.total_gen_time);
// Create popup HTML with stats
let html = `<h3>${statsType} Stats</h3>`;
html += createStatBlock('Chat Time', timeStirng);
html += createStatBlock('Total User Messages', stats.user_msg_count);
html += createStatBlock('Total Character Messages', stats.non_user_msg_count);
html += createStatBlock('Total User Words', stats.user_word_count);
html += createStatBlock('Total Character Words', stats.non_user_word_count);
html += createStatBlock('Swipes', stats.total_swipe_count);
callPopup(html, 'text');
}
async function userStatsHandler(charStats) {
// Get stats from server
let stats = await getStats(charStats);
// Calculate total stats
let totalStats = calculateTotalStats(stats);
console.log(totalStats);
// Create HTML with stats
createHtml('User', totalStats);
}
async function characterStatsHandler(charStats, characters, this_chid) {
// Get stats from server
let stats = await getStats(charStats);
// Get character stats
let myStats = stats[characters[this_chid].avatar];
// Create HTML with stats
createHtml('Character', myStats);
}
async function getStats(charStats) {
const response = await fetch("/getstats", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({}),
cache: "no-cache",
});
if (!response.ok) {
toastr.error('Stats could not be loaded. Try reloading the page.');
throw new Error('Error getting stats');
}
const data = await response.json();
return data;
}
export { userStatsHandler, characterStatsHandler, getStats };

View File

@@ -1877,6 +1877,11 @@ grammarly-extension {
overflow-y: hidden;
}
.rm_stat_block {
display: flex;
justify-content: space-between;
}
.large_dialogue_popup {
height: 90vh !important;
height: 90svh !important;

View File

@@ -132,7 +132,6 @@ function countWordsInString(str) {
* @return {object} An object containing the calculated statistics.
*/
const calculateStats = (chatsPath, item, index) => {
console.log('Calculating stats for', item);
const char_dir = path.join(chatsPath, item.replace('.png', ''));
let chat_size = 0;
let date_last_chat = 0;
@@ -152,7 +151,6 @@ const calculateStats = (chatsPath, item, index) => {
const chats = fs.readdirSync(char_dir);
if (Array.isArray(chats) && chats.length) {
for (const chat of chats) {
console.log(uniqueGenStartTimes);
const result = calculateTotalGenTimeAndWordCount(char_dir, chat, uniqueGenStartTimes);
stats.total_gen_time += result.totalGenTime || 0;
stats.user_word_count += result.userWordCount || 0;
@@ -164,7 +162,6 @@ const calculateStats = (chatsPath, item, index) => {
const chatStat = fs.statSync(path.join(char_dir, chat));
stats.chat_size += chatStat.size;
stats.date_last_chat = Math.max(stats.date_last_chat, chatStat.mtimeMs);
console.log(stats);
}
}
}