This commit is contained in:
nBiqoz
2025-10-06 19:16:20 +02:00
parent 96dd721fcb
commit 0f2adca44a
23 changed files with 1569 additions and 248 deletions

View File

@@ -46,24 +46,20 @@ export function UsageAnalytics() {
setLoading(true);
// Console log pour débugger les données balances
console.log("=== DONNÉES BALANCES RÉCUPÉRÉES ===");
console.log("Nombre total d'entrées balances:", balances.length);
console.log("Toutes les entrées balances:", balances);
// NOUVEAU : Console log pour débugger les utilisateurs
console.log("=== DONNÉES UTILISATEURS ===");
console.log("Nombre total d'utilisateurs:", users.length);
console.log("Premiers 5 utilisateurs:", users.slice(0, 5));
// Analyser les doublons
console.log("=== CALCUL DES STATISTIQUES ===");
console.log("Utilisateurs:", users.length);
console.log("Conversations:", conversations.length);
console.log("Transactions:", transactions.length);
console.log("Balances:", balances.length);
// Analyser les doublons dans les balances
const userCounts = new Map<string, number>();
balances.forEach(balance => {
balances.forEach((balance) => {
const userId = balance.user;
userCounts.set(userId, (userCounts.get(userId) || 0) + 1);
});
const duplicateUsers = Array.from(userCounts.entries()).filter(([_, count]) => count > 1);
const duplicateUsers = Array.from(userCounts.entries()).filter(([, count]) => count > 1);
console.log("Utilisateurs avec plusieurs entrées:", duplicateUsers);
// Afficher quelques exemples d'entrées
@@ -73,6 +69,29 @@ export function UsageAnalytics() {
const totalBrut = balances.reduce((sum, balance) => sum + (balance.tokenCredits || 0), 0);
console.log("Total brut (avec doublons potentiels):", totalBrut);
// Ajouter des logs détaillés pour comprendre le problème
console.log("=== DIAGNOSTIC DÉTAILLÉ ===");
// Analyser les doublons
const duplicateDetails = Array.from(userCounts.entries())
.filter(([, count]) => count > 1)
.map(([userId, count]) => {
const userBalances = balances.filter(b => b.user === userId);
const totalCredits = userBalances.reduce((sum, b) => sum + (b.tokenCredits || 0), 0);
return {
userId,
count,
totalCredits,
balances: userBalances.map(b => ({
credits: b.tokenCredits,
createdAt: b.createdAt,
updatedAt: b.updatedAt
}))
};
});
console.log("Détails des doublons:", duplicateDetails);
// NOUVEAU : Identifier les utilisateurs fantômes
console.log("=== ANALYSE DES UTILISATEURS FANTÔMES ===");
const userIds = new Set(users.map(user => user._id));
@@ -90,41 +109,58 @@ export function UsageAnalytics() {
console.log("Crédits des utilisateurs fantômes:", phantomCredits);
console.log("Crédits des vrais utilisateurs:", totalBrut - phantomCredits);
// Analyser les utilisateurs fantômes
const phantomDetails = uniquePhantomUsers.map(userId => {
const userBalances = balances.filter(b => b.user === userId);
const totalCredits = userBalances.reduce((sum, b) => sum + (b.tokenCredits || 0), 0);
return { userId, totalCredits, count: userBalances.length };
});
console.log("Détails des utilisateurs fantômes:", phantomDetails);
// Calculer les utilisateurs actifs (5 dernières minutes)
const fiveMinutesAgo = new Date();
fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5);
// Calculer les utilisateurs actifs (30 derniers jours)
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const activeUsers = users.filter((user) => {
const lastActivity = new Date(user.updatedAt || user.createdAt);
return lastActivity >= fiveMinutesAgo;
return lastActivity >= thirtyDaysAgo;
}).length;
// CORRECTION : Créer une map des crédits par utilisateur en évitant les doublons
// CORRECTION AMÉLIORÉE : Créer une map des crédits par utilisateur
const creditsMap = new Map<string, number>();
// Grouper les balances par utilisateur
const balancesByUser = new Map<string, LibreChatBalance[]>();
balances.forEach((balance) => {
const userId = balance.user;
if (!balancesByUser.has(userId)) {
balancesByUser.set(userId, []);
// Ignorer les utilisateurs fantômes (qui n'existent plus)
if (users.some(user => user._id === userId)) {
if (!balancesByUser.has(userId)) {
balancesByUser.set(userId, []);
}
balancesByUser.get(userId)!.push(balance);
}
balancesByUser.get(userId)!.push(balance);
});
// Pour chaque utilisateur, prendre seulement la dernière entrée
// Pour chaque utilisateur, calculer les crédits selon votre logique métier
balancesByUser.forEach((userBalances, userId) => {
if (userBalances.length > 0) {
// Trier par date de mise à jour (plus récent en premier)
// OPTION A: Prendre la balance la plus récente
const sortedBalances = userBalances.sort((a, b) => {
const aDate = new Date((a.updatedAt as string) || (a.createdAt as string) || 0);
const bDate = new Date((b.updatedAt as string) || (b.createdAt as string) || 0);
return bDate.getTime() - aDate.getTime();
});
creditsMap.set(userId, sortedBalances[0].tokenCredits || 0);
// Prendre la plus récente
const latestBalance = sortedBalances[0];
creditsMap.set(userId, latestBalance.tokenCredits || 0);
// OPTION B: Sommer toutes les balances (si c'est votre logique)
// const totalCredits = userBalances.reduce((sum, balance) => sum + (balance.tokenCredits || 0), 0);
// creditsMap.set(userId, totalCredits);
// OPTION C: Prendre la balance avec le plus de crédits
// const maxCredits = Math.max(...userBalances.map(b => b.tokenCredits || 0));
// creditsMap.set(userId, maxCredits);
}
});
@@ -167,12 +203,16 @@ export function UsageAnalytics() {
}
});
// CORRECTION : Calculer le total des crédits depuis la map corrigée
// Calculer le total des crédits depuis la map corrigée (sans doublons ni fantômes)
const totalCreditsUsed = Array.from(creditsMap.values()).reduce(
(sum, credits) => sum + credits,
0
);
console.log("=== RÉSULTATS CORRIGÉS ===");
console.log("Crédits totaux (sans doublons ni fantômes):", totalCreditsUsed);
console.log("Utilisateurs avec crédits:", creditsMap.size);
// Tous les utilisateurs triés par tokens puis conversations
const allUsers = Array.from(userStats.entries())
.map(([userId, stats]) => ({
@@ -242,7 +282,7 @@ export function UsageAnalytics() {
<CardContent>
<div className="text-2xl font-bold">{stats.totalUsers}</div>
<p className="text-xs text-muted-foreground">
{stats.activeUsers} actifs cette semaine
{stats.activeUsers} actifs ce mois
</p>
</CardContent>
</Card>