Spaces:
Running
Running
File size: 11,069 Bytes
b82d373 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
// statsHelper.js
import { getRequestHeaders, callPopup, characters, this_chid } from '../script.js';
import { humanizeGenTime } from './RossAscends-mods.js';
import { registerDebugFunction } from './power-user.js';
let charStats = {};
/**
* Creates an HTML stat block.
*
* @param {string} statName - The name of the stat to be displayed.
* @param {number|string} statValue - The value of the stat to be displayed.
* @returns {string} - An HTML string representing the stat block.
*/
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>`;
}
/**
* Verifies and returns a numerical stat value. If the provided stat is not a number, returns 0.
*
* @param {number|string} stat - The stat value to be checked and returned.
* @returns {number} - The stat value if it is a number, otherwise 0.
*/
function verifyStatValue(stat) {
return isNaN(Number(stat)) ? 0 : Number(stat);
}
/**
* Calculates total stats from character statistics.
*
* @returns {Object} - Object containing total statistics.
*/
function calculateTotalStats() {
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,
date_last_chat: 0,
date_first_chat: new Date('9999-12-31T23:59:59.999Z').getTime(),
};
for (let stats of Object.values(charStats)) {
totalStats.total_gen_time += verifyStatValue(stats.total_gen_time);
totalStats.user_msg_count += verifyStatValue(stats.user_msg_count);
totalStats.non_user_msg_count += verifyStatValue(
stats.non_user_msg_count,
);
totalStats.user_word_count += verifyStatValue(stats.user_word_count);
totalStats.non_user_word_count += verifyStatValue(
stats.non_user_word_count,
);
totalStats.total_swipe_count += verifyStatValue(
stats.total_swipe_count,
);
if (verifyStatValue(stats.date_last_chat) != 0) {
totalStats.date_last_chat = Math.max(
totalStats.date_last_chat,
stats.date_last_chat,
);
}
if (verifyStatValue(stats.date_first_chat) != 0) {
totalStats.date_first_chat = Math.min(
totalStats.date_first_chat,
stats.date_first_chat,
);
}
}
return totalStats;
}
/**
* Generates an HTML report of stats.
*
* This function creates an HTML report from the provided stats, including chat age,
* chat time, number of user messages and character messages, word count, and swipe count.
* The stat blocks are tailored depending on the stats type ("User" or "Character").
*
* @param {string} statsType - The type of stats (e.g., "User", "Character").
* @param {Object} stats - The stats data. Expected keys in this object include:
* total_gen_time - total generation time
* date_first_chat - timestamp of the first chat
* date_last_chat - timestamp of the most recent chat
* user_msg_count - count of user messages
* non_user_msg_count - count of non-user messages
* user_word_count - count of words used by the user
* non_user_word_count - count of words used by the non-user
* total_swipe_count - total swipe count
*/
function createHtml(statsType, stats) {
// Get time string
let timeStirng = humanizeGenTime(stats.total_gen_time);
let chatAge = 'Never';
if (stats.date_first_chat < Date.now()) {
chatAge = moment
.duration(stats.date_last_chat - stats.date_first_chat)
.humanize();
}
// Create popup HTML with stats
let html = `<h3>${statsType} Stats</h3>`;
if (statsType === 'User') {
html += createStatBlock('Chatting Since', `${chatAge} ago`);
} else {
html += createStatBlock('First Interaction', `${chatAge} ago`);
}
html += createStatBlock('Chat Time', timeStirng);
html += createStatBlock('User Messages', stats.user_msg_count);
html += createStatBlock(
'Character Messages',
stats.non_user_msg_count - stats.total_swipe_count,
);
html += createStatBlock('User Words', stats.user_word_count);
html += createStatBlock('Character Words', stats.non_user_word_count);
html += createStatBlock('Swipes', stats.total_swipe_count);
callPopup(html, 'text');
}
/**
* Handles the user stats by getting them from the server, calculating the total and generating the HTML report.
*/
async function userStatsHandler() {
// Get stats from server
await getStats();
// Calculate total stats
let totalStats = calculateTotalStats();
// Create HTML with stats
createHtml('User', totalStats);
}
/**
* Handles the character stats by getting them from the server and generating the HTML report.
*
* @param {Object} characters - Object containing character data.
* @param {string} this_chid - The character id.
*/
async function characterStatsHandler(characters, this_chid) {
// Get stats from server
await getStats();
// Get character stats
let myStats = charStats[characters[this_chid].avatar];
if (myStats === undefined) {
myStats = {
total_gen_time: 0,
user_msg_count: 0,
non_user_msg_count: 0,
user_word_count: 0,
non_user_word_count: countWords(characters[this_chid].first_mes),
total_swipe_count: 0,
date_last_chat: 0,
date_first_chat: new Date('9999-12-31T23:59:59.999Z').getTime(),
};
charStats[characters[this_chid].avatar] = myStats;
updateStats();
}
// Create HTML with stats
createHtml('Character', myStats);
}
/**
* Fetches the character stats from the server.
*/
async function getStats() {
const response = await fetch('/api/stats/get', {
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');
}
charStats = await response.json();
}
/**
* Asynchronously recreates the stats file from chat files.
*
* Sends a POST request to the "/api/stats/recreate" endpoint. If the request fails,
* it displays an error notification and throws an error.
*
* @throws {Error} If the request to recreate stats is unsuccessful.
*/
async function recreateStats() {
const response = await fetch('/api/stats/recreate', {
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');
}
else {
toastr.success('Stats file recreated successfully!');
}
}
/**
* Calculates the generation time based on start and finish times.
*
* @param {string} gen_started - The start time in ISO 8601 format.
* @param {string} gen_finished - The finish time in ISO 8601 format.
* @returns {number} - The difference in time in milliseconds.
*/
function calculateGenTime(gen_started, gen_finished) {
if (gen_started === undefined || gen_finished === undefined) {
return 0;
}
let startDate = new Date(gen_started);
let endDate = new Date(gen_finished);
return endDate.getTime() - startDate.getTime();
}
/**
* Sends a POST request to the server to update the statistics.
*/
async function updateStats() {
const response = await fetch('/api/stats/update', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify(charStats),
});
if (response.status !== 200) {
console.error('Failed to update stats');
console.log(response.status);
}
}
/**
* Returns the count of words in the given string.
* A word is a sequence of alphanumeric characters (including underscore).
*
* @param {string} str - The string to count words in.
* @returns {number} - Number of words.
*/
function countWords(str) {
const match = str.match(/\b\w+\b/g);
return match ? match.length : 0;
}
/**
* Handles stat processing for messages.
*
* @param {Object} line - Object containing message data.
* @param {string} type - The type of the message processing (e.g., 'append', 'continue', 'appendFinal', 'swipe').
* @param {Object} characters - Object containing character data.
* @param {string} this_chid - The character id.
* @param {string} oldMesssage - The old message that's being processed.
*/
async function statMesProcess(line, type, characters, this_chid, oldMesssage) {
if (this_chid === undefined || characters[this_chid] === undefined) {
return;
}
await getStats();
let stat = charStats[characters[this_chid].avatar];
if (!stat) {
stat = {
total_gen_time: 0,
user_word_count: 0,
non_user_msg_count: 0,
user_msg_count: 0,
total_swipe_count: 0,
date_first_chat: Date.now(),
date_last_chat: Date.now(),
};
}
stat.total_gen_time += calculateGenTime(
line.gen_started,
line.gen_finished,
);
if (line.is_user) {
if (type != 'append' && type != 'continue' && type != 'appendFinal') {
stat.user_msg_count++;
stat.user_word_count += countWords(line.mes);
} else {
let oldLen = oldMesssage.split(' ').length;
stat.user_word_count += countWords(line.mes) - oldLen;
}
} else {
// if continue, don't add a message, get the last message and subtract it from the word count of
// the new message
if (type != 'append' && type != 'continue' && type != 'appendFinal') {
stat.non_user_msg_count++;
stat.non_user_word_count += countWords(line.mes);
} else {
let oldLen = oldMesssage.split(' ').length;
stat.non_user_word_count += countWords(line.mes) - oldLen;
}
}
if (type === 'swipe') {
stat.total_swipe_count++;
}
stat.date_last_chat = Date.now();
stat.date_first_chat = Math.min(
stat.date_first_chat ?? new Date('9999-12-31T23:59:59.999Z').getTime(),
Date.now(),
);
updateStats();
}
export function initStats() {
$('.rm_stats_button').on('click', function () {
characterStatsHandler(characters, this_chid);
});
// Wait for debug functions to load, then add the refresh stats function
registerDebugFunction('refreshStats', 'Refresh Stat File', 'Recreates the stats file based on existing chat files', recreateStats);
}
export { userStatsHandler, characterStatsHandler, getStats, statMesProcess, charStats };
|