diff --git a/.claude/settings.local.json b/.claude/settings.local.json index e969f39..301b8f7 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -12,7 +12,8 @@ "Bash(node debug-search.js:*)", "Bash(node update-referent.js:*)", "Bash(node:*)", - "Bash(curl:*)" + "Bash(curl:*)", + "Bash(npx tsc:*)" ], "deny": [], "ask": [] diff --git a/components/dashboard/usage-analytics.tsx b/components/dashboard/usage-analytics.tsx index 9aa8daf..87b5f20 100644 --- a/components/dashboard/usage-analytics.tsx +++ b/components/dashboard/usage-analytics.tsx @@ -37,7 +37,7 @@ export function UsageAnalytics() { const { data: users = [] } = useCollection("users", { limit: 1000 }); const { data: conversations = [] } = useCollection("conversations", { limit: 1000 }); - const { data: transactions = [] } = useCollection("transactions", { limit: 1000 }); + const { data: transactions = [] } = useCollection("transactions", { limit: 10000 }); const { data: balances = [] } = useCollection("balances", { limit: 1000 }); const calculateStats = useCallback(() => { @@ -56,7 +56,7 @@ export function UsageAnalytics() { // Analyser les doublons dans les balances const userCounts = new Map(); balances.forEach((balance) => { - const userId = balance.user; + const userId = String(balance.user); userCounts.set(userId, (userCounts.get(userId) || 0) + 1); }); @@ -77,7 +77,7 @@ export function UsageAnalytics() { const duplicateDetails = Array.from(userCounts.entries()) .filter(([, count]) => count > 1) .map(([userId, count]) => { - const userBalances = balances.filter(b => b.user === userId); + const userBalances = balances.filter(b => String(b.user) === userId); const totalCredits = userBalances.reduce((sum, b) => sum + (b.tokenCredits || 0), 0); return { userId, @@ -96,7 +96,7 @@ export function UsageAnalytics() { // NOUVEAU : Identifier les utilisateurs fantômes console.log("=== ANALYSE DES UTILISATEURS FANTÔMES ==="); const userIds = new Set(users.map(user => user._id)); - const balanceUserIds = balances.map(balance => balance.user); + const balanceUserIds = balances.map(balance => String(balance.user)); const phantomUsers = balanceUserIds.filter(userId => !userIds.has(userId)); const uniquePhantomUsers = [...new Set(phantomUsers)]; @@ -105,7 +105,7 @@ export function UsageAnalytics() { // Calculer les crédits des utilisateurs fantômes const phantomCredits = balances - .filter(balance => uniquePhantomUsers.includes(balance.user)) + .filter(balance => uniquePhantomUsers.includes(String(balance.user))) .reduce((sum, balance) => sum + (balance.tokenCredits || 0), 0); console.log("Crédits des utilisateurs fantômes:", phantomCredits); @@ -113,7 +113,7 @@ export function UsageAnalytics() { // Analyser les utilisateurs fantômes const phantomDetails = uniquePhantomUsers.map(userId => { - const userBalances = balances.filter(b => b.user === userId); + const userBalances = balances.filter(b => String(b.user) === userId); const totalCredits = userBalances.reduce((sum, b) => sum + (b.tokenCredits || 0), 0); return { userId, totalCredits, count: userBalances.length }; }); @@ -134,13 +134,13 @@ export function UsageAnalytics() { // Grouper les balances par utilisateur const balancesByUser = new Map(); balances.forEach((balance) => { - const userId = balance.user; + const balanceUserId = String(balance.user); // Ignorer les utilisateurs fantômes (qui n'existent plus) - if (users.some(user => user._id === userId)) { - if (!balancesByUser.has(userId)) { - balancesByUser.set(userId, []); + if (users.some(user => user._id === balanceUserId)) { + if (!balancesByUser.has(balanceUserId)) { + balancesByUser.set(balanceUserId, []); } - balancesByUser.get(userId)!.push(balance); + balancesByUser.get(balanceUserId)!.push(balance); } }); @@ -186,17 +186,19 @@ export function UsageAnalytics() { }); // Calculer les conversations par utilisateur + // conv.user est un STRING conversations.forEach((conv) => { - const userStat = userStats.get(conv.user); + const userStat = userStats.get(String(conv.user)); if (userStat) { userStat.conversations++; } }); // Calculer les tokens par utilisateur depuis les transactions + // transaction.user est un ObjectId, on le convertit en string let totalTokensConsumed = 0; transactions.forEach((transaction) => { - const userStat = userStats.get(transaction.user); + const userStat = userStats.get(String(transaction.user)); if (userStat && transaction.rawAmount) { const tokens = Math.abs(Number(transaction.rawAmount) || 0); userStat.tokens += tokens; diff --git a/debug-analytics.js b/debug-analytics.js new file mode 100644 index 0000000..fa26521 --- /dev/null +++ b/debug-analytics.js @@ -0,0 +1,27 @@ +const { MongoClient } = require('mongodb'); + +async function debug() { + const uri = 'mongodb://7qV5rRanD6UwANNO:NK1EFfaKpJZcTQlmm7pDUUI7Yk7yqxN6@51.254.197.189:27017/librechat?authSource=admin'; + const client = new MongoClient(uri); + await client.connect(); + const db = client.db('librechat'); + + // Vérifier les types + const user = await db.collection('users').findOne({}); + const tx = await db.collection('transactions').findOne({}); + const conv = await db.collection('conversations').findOne({}); + + console.log('=== TYPES DES IDs ==='); + console.log('user._id:', typeof user._id, '->', user._id); + console.log('transaction.user:', typeof tx.user, '->', tx.user); + console.log('conversation.user:', typeof conv.user, '->', conv.user); + + console.log('\n=== COMPARAISONS ==='); + console.log('user._id === tx.user:', user._id === tx.user); + console.log('String(user._id) === String(tx.user):', String(user._id) === String(tx.user)); + console.log('user._id.toString() === conv.user:', user._id.toString() === conv.user); + + await client.close(); +} + +debug().catch(console.error);