Run this script in your browser console while logged into Moonshot platform:
// Moonshot Usage Data Fetcher - Run this in browser console
// Make sure you're logged in to https://platform.moonshot.cn first
(async function() {
console.log('🚀 Starting Moonshot usage data fetch...');
// Extract organization ID from current URL or cookies
const extractOrgId = () => {
// Try to get from URL
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('oid')) return urlParams.get('oid');
// Try to get from localStorage or cookies
const localStorageKeys = Object.keys(localStorage);
for (let key of localStorageKeys) {
if (key.includes('org-')) return key.split('-')[1];
}
// Common pattern from the examples
const selectedOrg = localStorage.getItem('selectedOrganization');
if (!selectedOrg) {
console.error('❌ No selectedOrganization found in localStorage. Please set it using localStorage.setItem("selectedOrganization", "your-org-id");');
alert('❌ 错误: 未找到组织ID。请在localStorage中设置"selectedOrganization"。');
return null; // Return null or throw an error to indicate failure
}
return selectedOrg;
};
const orgId = extractOrgId();
if (!orgId) {
console.error('❌ Operation cancelled due to missing organization ID.');
return; // Exit if orgId is not available
}
console.log(`📋 Using org ID: ${orgId}`);
// Get Bearer token from localStorage
const authToken = localStorage.getItem('token');
if (!authToken) {
console.error('❌ No Bearer token found in localStorage (key: "token")');
console.log('💡 Make sure you are logged in to https://platform.moonshot.cn');
return;
}
console.log('🔐 Bearer token found in localStorage');
// Get date range for last 30 days
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
const startTime = startDate.getTime();
const endTime = endDate.getTime();
console.log(`📅 Fetching data from ${startDate.toLocaleDateString()} to ${endDate.toLocaleDateString()}`);
const allRequests = [];
let page = 0;
let totalRecords = 0;
async function fetchPage(pageNum) {
const url = new URL('https://platform.moonshot.cn/api');
url.searchParams.set('start', startTime.toString());
url.searchParams.set('end', endTime.toString());
url.searchParams.set('page', pageNum.toString());
url.searchParams.set('limit', '100');
url.searchParams.set('desc', 'true');
url.searchParams.set('oid', orgId);
url.searchParams.set('endpoint', 'organizationRequests');
const response = await fetch(url.toString(), {
method: 'GET',
headers: {
'accept': '*/*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
'authorization': `Bearer ${authToken}`,
'cache-control': 'no-cache',
'pragma': 'no-cache',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin'
},
credentials: 'include'
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
try {
// Fetch first page to get total count
console.log('📡 Fetching page 1...');
const firstPage = await fetchPage(0);
if (firstPage.code !== 0) {
throw new Error(`API Error: ${firstPage.message}`);
}
totalRecords = firstPage.data.total;
allRequests.push(...firstPage.data.requests);
console.log(`📊 Found ${totalRecords} total records`);
// Calculate pages needed
const totalPages = Math.ceil(totalRecords / 100);
console.log(`📄 Need to fetch ${totalPages} pages total`);
// Fetch remaining pages with progress
for (page = 1; page < totalPages; page++) {
console.log(`📡 Fetching page ${page + 1}/${totalPages}...`);
const pageData = await fetchPage(page);
if (pageData.code === 0 && pageData.data.requests) {
allRequests.push(...pageData.data.requests);
}
// Small delay to be respectful
await new Promise(resolve => setTimeout(resolve, 300));
}
// Process the data
console.log('🔧 Processing data...');
const processedData = {
fetchedAt: new Date().toISOString(),
totalRequests: allRequests.length,
dateRange: {
start: startDate.toISOString(),
end: endDate.toISOString()
},
summary: {
totalTokens: allRequests.reduce((sum, req) => sum + (req.pt || 0) + (req.rt || 0), 0),
totalCachedInputTokens: allRequests.reduce((sum, req) => sum + (req.ct || 0), 0),
totalInputTokens: allRequests.reduce((sum, req) => sum + (req.pt || 0), 0),
totalOutputTokens: allRequests.reduce((sum, req) => sum + (req.rt || 0), 0),
uniqueModels: [...new Set(allRequests.map(req => req.model_id))].sort(),
uniqueKeys: [...new Set(allRequests.map(req => req.key))].sort()
},
requests: allRequests.map(req => ({
id: req.id,
time: req.time,
timestamp: new Date(req.time).getTime(),
cachedInputTokens: req.ct || 0,
inputTokens: req.pt || 0,
outputTokens: req.rt || 0,
uncachedInputTokens: (req.pt || 0) - (req.ct || 0),
model: req.model_id,
apiKey: req.key,
date: req.time.split('T')[0],
hour: new Date(req.time).getHours()
}))
};
// Download the file
const blob = new Blob([JSON.stringify(processedData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `moonshot-usage-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log('✅ Success! File downloaded as:', a.download);
console.log(`📊 Summary:`);
console.log(` ${processedData.totalRequests} requests`);
console.log(` ${processedData.summary.totalTokens.toLocaleString()} total tokens`);
console.log(` ${processedData.summary.totalCachedInputTokens.toLocaleString()} cached input tokens`);
console.log(` ${processedData.summary.totalInputTokens.toLocaleString()} total input tokens`);
console.log(` ${processedData.summary.totalOutputTokens.toLocaleString()} total output tokens`);
console.log(` ${processedData.summary.uniqueModels.length} models: ${processedData.summary.uniqueModels.join(', ')}`);
} catch (error) {
console.error('❌ Error:', error.message);
console.log('💡 Make sure you are logged in to https://platform.moonshot.cn in this browser');
}
})();
// Usage Instructions:
// 1. Go to https://platform.moonshot.cn and log in
// 2. Open browser console (F12 → Console)
// 3. Copy and paste this entire script
// 4. Press Enter to run
// 5. Your JSON file will be downloaded automatically
Install this userscript to add an "Export Usage Data" button to Moonshot platform:
// ==UserScript==
// @name Moonshot Usage Export Button
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Add a button to export Moonshot usage data as JSON with one click
// @author You
// @match https://platform.moonshot.cn/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Create the export button
const createExportButton = () => {
const button = document.createElement('button');
button.textContent = 'Export Usage Data';
button.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 10000;
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
transition: background-color 0.3s;
`;
button.addEventListener('mouseenter', () => {
button.style.background = '#0056b3';
});
button.addEventListener('mouseleave', () => {
button.style.background = '#007bff';
});
button.addEventListener('click', exportUsageData);
return button;
};
// Main export function
const exportUsageData = async () => {
const button = document.getElementById('moonshot-export-btn');
button.textContent = 'Exporting...';
button.disabled = true;
button.style.background = '#6c757d';
try {
console.log('🚀 Starting Moonshot usage data export...');
// Extract organization ID from current URL or cookies
const extractOrgId = () => {
// Try to get from URL
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('oid')) return urlParams.get('oid');
// Try to get from localStorage or cookies
const localStorageKeys = Object.keys(localStorage);
for (let key of localStorageKeys) {
if (key.includes('org-')) return key.split('-')[1];
}
// Common pattern from the examples
const selectedOrg = localStorage.getItem('selectedOrganization');
if (!selectedOrg) {
alert('❌ 错误: 未找到组织ID。请在localStorage中设置"selectedOrganization"。');
return null; // Return null or throw an error to indicate failure
}
return selectedOrg;
};
const orgId = extractOrgId();
if (!orgId) {
console.error('❌ Operation cancelled due to missing organization ID.');
return; // Exit if orgId is not available
}
console.log(`📋 Using org ID: ${orgId}`);
// Get Bearer token from localStorage
const authToken = localStorage.getItem('token');
if (!authToken) {
alert('❌ No Bearer token found. Make sure you are logged in to Moonshot.');
return;
}
console.log('🔐 Bearer token found in localStorage');
// Get date range for last 30 days
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
const startTime = startDate.getTime();
const endTime = endDate.getTime();
console.log(`📅 Fetching data from ${startDate.toLocaleDateString()} to ${endDate.toLocaleDateString()}`);
const allRequests = [];
let page = 0;
let totalRecords = 0;
async function fetchPage(pageNum) {
const url = new URL('https://platform.moonshot.cn/api');
url.searchParams.set('start', startTime.toString());
url.searchParams.set('end', endTime.toString());
url.searchParams.set('page', pageNum.toString());
url.searchParams.set('limit', '100');
url.searchParams.set('desc', 'true');
url.searchParams.set('oid', orgId);
url.searchParams.set('endpoint', 'organizationRequests');
const response = await fetch(url.toString(), {
method: 'GET',
headers: {
'accept': '*/*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
'authorization': `Bearer ${authToken}`,
'cache-control': 'no-cache',
'pragma': 'no-cache',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin'
},
credentials: 'include'
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
// Fetch first page to get total count
console.log('📡 Fetching page 1...');
const firstPage = await fetchPage(0);
if (firstPage.code !== 0) {
throw new Error(`API Error: ${firstPage.message}`);
}
totalRecords = firstPage.data.total;
allRequests.push(...firstPage.data.requests);
console.log(`📊 Found ${totalRecords} total records`);
// Calculate pages needed
const totalPages = Math.ceil(totalRecords / 100);
console.log(`📄 Need to fetch ${totalPages} pages total`);
// Fetch remaining pages with progress
for (page = 1; page < totalPages; page++) {
console.log(`📡 Fetching page ${page + 1}/${totalPages}...`);
const pageData = await fetchPage(page);
if (pageData.code === 0 && pageData.data.requests) {
allRequests.push(...pageData.data.requests);
}
// Small delay to be respectful
await new Promise(resolve => setTimeout(resolve, 300));
}
// Process the data
console.log('🔧 Processing data...');
const processedData = {
fetchedAt: new Date().toISOString(),
totalRequests: allRequests.length,
dateRange: {
start: startDate.toISOString(),
end: endDate.toISOString()
},
summary: {
totalTokens: allRequests.reduce((sum, req) => sum + (req.pt || 0) + (req.rt || 0), 0),
totalCachedInputTokens: allRequests.reduce((sum, req) => sum + (req.ct || 0), 0),
totalInputTokens: allRequests.reduce((sum, req) => sum + (req.pt || 0), 0),
totalOutputTokens: allRequests.reduce((sum, req) => sum + (req.rt || 0), 0),
uniqueModels: [...new Set(allRequests.map(req => req.model_id))].sort(),
uniqueKeys: [...new Set(allRequests.map(req => req.key))].sort()
},
requests: allRequests.map(req => ({
id: req.id,
time: req.time,
timestamp: new Date(req.time).getTime(),
cachedInputTokens: req.ct || 0,
inputTokens: req.pt || 0,
outputTokens: req.rt || 0,
uncachedInputTokens: (req.pt || 0) - (req.ct || 0),
model: req.model_id,
apiKey: req.key,
date: req.time.split('T')[0],
hour: new Date(req.time).getHours()
}))
};
// Download the file
const blob = new Blob([JSON.stringify(processedData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `moonshot-usage-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log('✅ Success! File downloaded as:', a.download);
alert(`✅ Export complete! ${processedData.totalRequests} requests exported.`);
} catch (error) {
console.error('❌ Error:', error.message);
alert(`❌ Error: ${error.message}`);
} finally {
// Reset button
button.textContent = 'Export Usage Data';
button.disabled = false;
button.style.background = '#007bff';
}
};
// Add button to page
const addButton = () => {
// Remove existing button if any
const existingButton = document.getElementById('moonshot-export-btn');
if (existingButton) {
existingButton.remove();
}
const button = createExportButton();
button.id = 'moonshot-export-btn';
document.body.appendChild(button);
};
// Wait for page to load then add button
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addButton);
} else {
addButton();
}
// Re-add button on page changes (for SPA navigation)
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
setTimeout(addButton, 1000); // Add button after navigation
}
}).observe(document, { subtree: true, childList: true });
})();
Instructions: • Browser Console: Copy the script above, open Moonshot platform, press F12 → Console, paste and run
• Userscript: Install Tampermonkey extension, create new script, paste the code above, then visit Moonshot platform