Enhances dashboard metrics and session handling with word cloud data and country metrics

This commit is contained in:
2025-05-22 07:31:24 +02:00
parent 7762061850
commit 2b75c53241
6 changed files with 509 additions and 128 deletions

View File

@ -4,13 +4,308 @@ import {
DayMetrics,
CategoryMetrics,
LanguageMetrics,
CountryMetrics, // Added CountryMetrics
MetricsResult,
WordCloudWord, // Added WordCloudWord
} from "./types";
interface CompanyConfig {
sentimentAlert?: number;
}
// List of common stop words - this can be expanded
const stopWords = new Set([
"assistant",
"user",
// Web
"com",
"www",
"http",
"https",
"www2",
"href",
"html",
"php",
"js",
"css",
"xml",
"json",
"txt",
"jpg",
"jpeg",
"png",
"gif",
"bmp",
"svg",
"org",
"net",
"co",
"io",
// English stop words
"a",
"an",
"the",
"is",
"are",
"was",
"were",
"be",
"been",
"being",
"have",
"has",
"had",
"do",
"does",
"did",
"will",
"would",
"should",
"can",
"could",
"may",
"might",
"must",
"am",
"i",
"you",
"he",
"she",
"it",
"we",
"they",
"me",
"him",
"her",
"us",
"them",
"my",
"your",
"his",
"its",
"our",
"their",
"mine",
"yours",
"hers",
"ours",
"theirs",
"to",
"of",
"in",
"on",
"at",
"by",
"for",
"with",
"about",
"against",
"between",
"into",
"through",
"during",
"before",
"after",
"above",
"below",
"from",
"up",
"down",
"out",
"off",
"over",
"under",
"again",
"further",
"then",
"once",
"here",
"there",
"when",
"where",
"why",
"how",
"all",
"any",
"both",
"each",
"few",
"more",
"most",
"other",
"some",
"such",
"no",
"nor",
"not",
"only",
"own",
"same",
"so",
"than",
"too",
"very",
"s",
"t",
"just",
"don",
"shouldve",
"now",
"d",
"ll",
"m",
"o",
"re",
"ve",
"y",
"ain",
"aren",
"couldn",
"didn",
"doesn",
"hadn",
"hasn",
"haven",
"isn",
"ma",
"mightn",
"mustn",
"needn",
"shan",
"shouldn",
"wasn",
"weren",
"won",
"wouldn",
"hi",
"hello",
"thanks",
"thank",
"please",
"ok",
"okay",
"yes",
"yeah",
"bye",
"goodbye",
// French stop words
"la",
"le",
"les",
"un",
"une",
"des",
"et",
"ou",
"mais",
"donc",
// Dutch stop words
"dit",
"ben",
"de",
"het",
"ik",
"jij",
"hij",
"zij",
"wij",
"jullie",
"deze",
"dit",
"dat",
"die",
"een",
"en",
"of",
"maar",
"want",
"omdat",
"dus",
"als",
"ook",
"dan",
"nu",
"nog",
"al",
"naar",
"voor",
"van",
"door",
"met",
"bij",
"tot",
"om",
"over",
"tussen",
"onder",
"boven",
"tegen",
"aan",
"uit",
"sinds",
"tijdens",
"binnen",
"buiten",
"zonder",
"volgens",
"dankzij",
"ondanks",
"behalve",
"mits",
"tenzij",
"hoewel",
"alhoewel",
"toch",
"anders",
"echter",
"wel",
"niet",
"geen",
"iets",
"niets",
"veel",
"weinig",
"meer",
"meest",
"elk",
"ieder",
"sommige",
"hoe",
"wat",
"waar",
"wie",
"wanneer",
"waarom",
"welke",
"wordt",
"worden",
"werd",
"werden",
"geworden",
"zijn",
"ben",
"bent",
"was",
"waren",
"geweest",
"hebben",
"heb",
"hebt",
"heeft",
"had",
"hadden",
"gehad",
"kunnen",
"kan",
"kunt",
"kon",
"konden",
"zullen",
"zal",
"zult",
// Add more domain-specific stop words if necessary
]);
export function sessionMetrics(
sessions: ChatSession[],
companyConfig: CompanyConfig = {}
@ -19,6 +314,7 @@ export function sessionMetrics(
const byDay: DayMetrics = {};
const byCategory: CategoryMetrics = {};
const byLanguage: LanguageMetrics = {};
const byCountry: CountryMetrics = {}; // Added for country data
const tokensByDay: DayMetrics = {};
const tokensCostByDay: DayMetrics = {};
@ -40,12 +336,15 @@ export function sessionMetrics(
let totalDuration = 0;
let durationCount = 0;
const wordCounts: { [key: string]: number } = {}; // For WordCloud
sessions.forEach((s) => {
const day = s.startTime.toISOString().slice(0, 10);
byDay[day] = (byDay[day] || 0) + 1;
if (s.category) byCategory[s.category] = (byCategory[s.category] || 0) + 1;
if (s.language) byLanguage[s.language] = (byLanguage[s.language] || 0) + 1;
if (s.country) byCountry[s.country] = (byCountry[s.country] || 0) + 1; // Populate byCountry
// Process token usage by day
if (s.tokens) {
@ -88,6 +387,24 @@ export function sessionMetrics(
totalTokens += s.tokens || 0;
totalTokensEur += s.tokensEur || 0;
// Process transcript for WordCloud
if (s.transcriptContent) {
const words = s.transcriptContent.toLowerCase().match(/\b\w+\b/g); // Split into words, lowercase
if (words) {
words.forEach((word) => {
const cleanedWord = word.replace(/[^a-z0-9]/gi, ""); // Remove punctuation
if (
cleanedWord &&
!stopWords.has(cleanedWord) &&
cleanedWord.length > 2
) {
// Check if not a stop word and length > 2
wordCounts[cleanedWord] = (wordCounts[cleanedWord] || 0) + 1;
}
});
}
}
});
// Now add sentiment alert logic:
@ -107,13 +424,20 @@ export function sessionMetrics(
const avgSessionLength =
durationCount > 0 ? totalDuration / durationCount : null;
// Prepare wordCloudData
const wordCloudData: WordCloudWord[] = Object.entries(wordCounts)
.map(([text, value]) => ({ text, value }))
.sort((a, b) => b.value - a.value)
.slice(0, 500); // Take top 500 words
return {
totalSessions: total,
avgSessionsPerDay,
avgSessionLength,
days: byDay,
languages: byLanguage,
categories: byCategory,
categories: byCategory, // This will be empty if we are not using categories for word cloud
countries: byCountry, // Added countries to the result
belowThresholdCount: belowThreshold,
// Additional metrics not in the interface - using type assertion
escalatedCount: escalated,
@ -131,5 +455,6 @@ export function sessionMetrics(
sentimentNegativeCount: sentimentNegative,
tokensByDay,
tokensCostByDay,
wordCloudData, // Added word cloud data
};
}

View File

@ -74,6 +74,15 @@ export interface LanguageMetrics {
[language: string]: number;
}
export interface CountryMetrics {
[country: string]: number;
}
export interface WordCloudWord {
text: string;
value: number;
}
export interface MetricsResult {
totalSessions: number;
avgSessionsPerDay: number;
@ -81,6 +90,7 @@ export interface MetricsResult {
days: DayMetrics;
languages: LanguageMetrics;
categories: CategoryMetrics;
countries: CountryMetrics; // Added for geographic distribution
belowThresholdCount: number;
// Additional properties for dashboard
escalatedCount?: number;
@ -98,6 +108,7 @@ export interface MetricsResult {
sentimentNegativeCount?: number;
tokensByDay?: DayMetrics;
tokensCostByDay?: DayMetrics;
wordCloudData?: WordCloudWord[]; // Added for transcript-based word cloud
}
export interface ApiResponse<T> {