mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 08:32:09 +01:00
feat: initialize project with Next.js, Prisma, and Tailwind CSS
- Add package.json with dependencies and scripts for Next.js and Prisma - Implement API routes for session management, user authentication, and company configuration - Create database schema for Company, User, and Session models in Prisma - Set up authentication with NextAuth and JWT - Add password reset functionality and user registration endpoint - Configure Tailwind CSS and PostCSS for styling - Implement metrics and dashboard settings API endpoints
This commit is contained in:
85
lib/metrics.ts
Normal file
85
lib/metrics.ts
Normal file
@ -0,0 +1,85 @@
|
||||
// Functions to calculate metrics over sessions
|
||||
import { ChatSession, DayMetrics, CategoryMetrics, LanguageMetrics, MetricsResult } from './types';
|
||||
|
||||
interface CompanyConfig {
|
||||
sentimentAlert?: number;
|
||||
}
|
||||
|
||||
export function sessionMetrics(sessions: ChatSession[], companyConfig: CompanyConfig = {}): MetricsResult {
|
||||
const total = sessions.length;
|
||||
const byDay: DayMetrics = {};
|
||||
const byCategory: CategoryMetrics = {};
|
||||
const byLanguage: LanguageMetrics = {};
|
||||
let escalated = 0, forwarded = 0;
|
||||
let totalSentiment = 0, sentimentCount = 0;
|
||||
let totalResponse = 0, responseCount = 0;
|
||||
let totalTokens = 0, totalTokensEur = 0;
|
||||
|
||||
// Calculate total session duration in minutes
|
||||
let totalDuration = 0;
|
||||
let durationCount = 0;
|
||||
|
||||
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.endTime) {
|
||||
const duration = (s.endTime.getTime() - s.startTime.getTime()) / (1000 * 60); // minutes
|
||||
totalDuration += duration;
|
||||
durationCount++;
|
||||
}
|
||||
|
||||
if (s.escalated) escalated++;
|
||||
if (s.forwardedHr) forwarded++;
|
||||
|
||||
if (s.sentiment != null) {
|
||||
totalSentiment += s.sentiment;
|
||||
sentimentCount++;
|
||||
}
|
||||
|
||||
if (s.avgResponseTime != null) {
|
||||
totalResponse += s.avgResponseTime;
|
||||
responseCount++;
|
||||
}
|
||||
|
||||
totalTokens += s.tokens || 0;
|
||||
totalTokensEur += s.tokensEur || 0;
|
||||
});
|
||||
|
||||
// Now add sentiment alert logic:
|
||||
let belowThreshold = 0;
|
||||
const threshold = companyConfig.sentimentAlert ?? null;
|
||||
if (threshold != null) {
|
||||
for (const s of sessions) {
|
||||
if (s.sentiment != null && s.sentiment < threshold) belowThreshold++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate average sessions per day
|
||||
const dayCount = Object.keys(byDay).length;
|
||||
const avgSessionsPerDay = dayCount > 0 ? total / dayCount : 0;
|
||||
|
||||
// Calculate average session length
|
||||
const avgSessionLength = durationCount > 0 ? totalDuration / durationCount : null;
|
||||
|
||||
return {
|
||||
totalSessions: total,
|
||||
avgSessionsPerDay,
|
||||
avgSessionLength,
|
||||
days: byDay,
|
||||
languages: byLanguage,
|
||||
categories: byCategory,
|
||||
belowThresholdCount: belowThreshold,
|
||||
// Additional metrics not in the interface - using type assertion
|
||||
escalatedCount: escalated,
|
||||
forwardedCount: forwarded,
|
||||
avgSentiment: sentimentCount ? totalSentiment / sentimentCount : null,
|
||||
avgResponseTime: responseCount ? totalResponse / responseCount : null,
|
||||
totalTokens,
|
||||
totalTokensEur,
|
||||
sentimentThreshold: threshold,
|
||||
} as MetricsResult;
|
||||
}
|
||||
Reference in New Issue
Block a user