Skip to content

Commit da18281

Browse files
committed
feat: Upgrade to version 3.0.1 with model usage report parsing
- Updated package version to 3.0.1 and added exports for Node.js and web environments. - Removed deprecated functions for reading GitHub usage reports and replaced them with new model usage report functions. - Introduced new types for model usage reports, including ModelUsageReport and ModelUsageReportLine. - Implemented parsing functions for model usage reports, including readModelUsageReport and readModelUsageReportLine. - Added support for reading model usage report files both synchronously and asynchronously. - Updated tests to cover new model usage report functionality and added example scripts for usage. - Created a detailed README for model usage report parsing, including usage examples and CSV format requirements.
1 parent c38945d commit da18281

13 files changed

Lines changed: 906 additions & 3103 deletions

README.md

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,124 @@
11
# GitHub Usage Report Library
22

3-
A TypeScript library to read and process GitHub usage data from CSV files.
3+
A TypeScript library to read and process GitHub usage data and model usage data from CSV files.
44

55
## Features
66

77
- Parse GitHub Actions usage reports from CSV files
8+
- Parse model usage reports (e.g., AI model interactions) from CSV files
89
- Support for both streaming (async) and direct (sync) file reading
10+
- Works in both Node.js and web environments
911
- TypeScript support with full type definitions
1012
- Optional line-by-line processing callbacks
1113

1214
## Installation
1315

1416
```bash
15-
npm install
17+
npm install github-usage-report
1618
```
1719

1820
## Usage
1921

20-
### Reading a Usage Report (Async)
22+
This library supports both Node.js and web environments through different import paths:
2123

22-
```typescript
23-
import { readGithubUsageReportFile } from './src/index';
24+
### Node.js Usage (with file system access)
2425

25-
// Basic usage
26-
const report = await readGithubUsageReportFile('path/to/usage-report.csv');
27-
console.log(`Report covers ${report.days} days from ${report.startDate} to ${report.endDate}`);
26+
For Node.js applications, you can import the full library which includes file reading capabilities:
2827

29-
// With line-by-line callback
30-
const report = await readGithubUsageReportFile('path/to/usage-report.csv', (line) => {
28+
```typescript
29+
import { readGithubUsageReportFile, readGithubUsageReportFileSync, readModelUsageReportFile, readModelUsageReportFileSync } from 'github-usage-report';
30+
31+
// GitHub Actions usage reports
32+
const githubReport = await readGithubUsageReportFile('path/to/usage-report.csv', (line) => {
3133
console.log(`Processing: ${line.date} - ${line.product}`);
3234
});
35+
36+
// Model usage reports
37+
const modelReport = await readModelUsageReportFile('path/to/model-usage.csv', (line) => {
38+
console.log(`Processing: ${line.user} - ${line.model}`);
39+
});
40+
41+
// Sync file reading
42+
const report = await readGithubUsageReportFileSync('path/to/usage-report.csv');
43+
console.log(`Total lines: ${report.lines.length}`);
3344
```
3445

35-
### Reading a Usage Report (Sync)
46+
### Web/Browser Usage (without file system dependencies)
47+
48+
For web applications or environments where you don't need file system access, import from the core module:
3649

3750
```typescript
38-
import { readGithubUsageReportFileSync } from './src/index';
51+
import { readGithubUsageReport, readModelUsageReport } from 'github-usage-report/core';
3952

40-
const report = await readGithubUsageReportFileSync('path/to/usage-report.csv');
41-
console.log(`Total lines: ${report.lines.length}`);
53+
// Parse GitHub Actions CSV data from string (e.g., from a file upload or API)
54+
const githubCsvData = `Date,Product,SKU,...
55+
2023-01-01,Actions,minutes,...`;
56+
57+
const githubReport = await readGithubUsageReport(githubCsvData);
58+
59+
// Parse model usage CSV data from string
60+
const modelCsvData = `Timestamp,User,Model,Requests Used,Exceeds Monthly Quota,Total Monthly Quota
61+
2025-06-02T22:34:09Z,bspann,claude-sonnet-4,1.00,false,Unlimited`;
62+
63+
const modelReport = await readModelUsageReport(modelCsvData);
64+
```
65+
console.log(`Report covers ${report.days} days from ${report.startDate} to ${report.endDate}`);
66+
```
67+
68+
### Universal Usage
69+
70+
You can also import specific functions based on your needs:
71+
72+
```typescript
73+
// Import only what you need from core (works everywhere)
74+
import { readGithubUsageReport, readModelUsageReport, UsageReport, UsageReportLine, ModelUsageReport, ModelUsageReportLine } from 'github-usage-report/core';
75+
76+
// Import Node.js specific functions (works only in Node.js)
77+
import { readGithubUsageReportFile, readGithubUsageReportFileSync, readModelUsageReportFile, readModelUsageReportFileSync } from 'github-usage-report/node';
4278
```
4379

4480
### Report Structure
4581

46-
The library returns a `UsageReport` object with the following structure:
82+
The library returns different report objects based on the data type:
4783

84+
#### GitHub Usage Report
4885
```typescript
4986
{
5087
startDate: Date, // First date in the report
5188
endDate: Date, // Last date in the report
5289
days: number, // Number of days covered
53-
lines: UsageReportLine[] // Array of parsed usage data
90+
lines: UsageReportLine[] // Array of parsed GitHub usage data
5491
}
5592
```
5693

94+
#### Model Usage Report
95+
```typescript
96+
{
97+
startDate: Date, // First timestamp in the report
98+
endDate: Date, // Last timestamp in the report
99+
days: number, // Number of days covered
100+
lines: ModelUsageReportLine[] // Array of parsed model usage data
101+
}
102+
```
103+
104+
### Model Usage Report Format
105+
106+
The model usage report expects CSV files with this format:
107+
108+
```csv
109+
Timestamp,User,Model,Requests Used,Exceeds Monthly Quota,Total Monthly Quota
110+
2025-06-02T22:34:09Z,bspann,claude-sonnet-4,1.00,false,Unlimited
111+
2025-06-02T22:35:15Z,jdoe,gpt-4,2.50,false,100
112+
```
113+
114+
**Fields:**
115+
- **Timestamp**: ISO 8601 format (e.g., `2025-06-02T22:34:09Z`)
116+
- **User**: String username
117+
- **Model**: String model name
118+
- **Requests Used**: Numeric value (can be decimal)
119+
- **Exceeds Monthly Quota**: Boolean (`true` or `false`)
120+
- **Total Monthly Quota**: String (either "Unlimited" or a numeric value)
121+
57122
## Getting Your GitHub Usage Report
58123

59124
To generate a GitHub usage report:

examples/model-usage-example.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const { readModelUsageReport } = require('../dist/usage-report');
2+
const fs = require('fs');
3+
4+
// Example CSV data for model usage report (similar to premium_interactions_b16336c228824bf39744429a39994e16.csv)
5+
const csvData = `Timestamp,User,Model,Requests Used,Exceeds Monthly Quota,Total Monthly Quota
6+
2025-06-02T22:34:09Z,bspann,claude-sonnet-4,1.00,false,Unlimited
7+
2025-06-02T19:19:05Z,bspann,claude-sonnet-4,1.00,false,Unlimited
8+
2025-06-02T18:57:29Z,bspann,claude-sonnet-4,1.00,false,Unlimited
9+
2025-06-02T05:42:25Z,bspann,claude-sonnet-4,1.00,false,Unlimited`;
10+
11+
async function example() {
12+
try {
13+
const report = await readModelUsageReport(csvData);
14+
15+
console.log('Model Usage Report Summary:');
16+
console.log(`Period: ${report.startDate.toISOString()} to ${report.endDate.toISOString()}`);
17+
console.log(`Duration: ${report.days} days`);
18+
console.log(`Total entries: ${report.lines.length}`);
19+
console.log();
20+
21+
console.log('Usage details:');
22+
report.lines.forEach((line, index) => {
23+
console.log(`${index + 1}. ${line.user} used ${line.model} - ${line.requestsUsed} requests`);
24+
console.log(` Quota: ${line.totalMonthlyQuota}, Exceeds: ${line.exceedsMonthlyQuota}`);
25+
console.log(` Timestamp: ${line.timestamp.toISOString()}`);
26+
console.log();
27+
});
28+
// Find users who exceeded quota
29+
const exceededQuota = report.lines.filter(line => line.exceedsMonthlyQuota);
30+
if (exceededQuota.length > 0) {
31+
console.log('Users who exceeded quota:');
32+
exceededQuota.forEach(line => {
33+
console.log(`- ${line.user} (${line.model})`);
34+
});
35+
} else {
36+
console.log('No users exceeded their quota.');
37+
}
38+
39+
} catch (error) {
40+
console.error('Error parsing model usage report:', error);
41+
}
42+
}
43+
44+
example();

examples/node-example.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Example usage for Node.js environments
2+
import { readGithubUsageReportFile, readGithubUsageReportFileSync } from '../dist/node.js';
3+
4+
async function nodeExample() {
5+
try {
6+
console.log('=== Async File Reading ===');
7+
const report = await readGithubUsageReportFile('./tests/data/usageReport_1_0b650fc20d564ed2bddf337ac27c7a57.csv', (line) => {
8+
console.log(`${line.date.toLocaleDateString()} - ${line.product}\t$${line.netAmount.toFixed(2)}`);
9+
});
10+
11+
console.log(`\nTotal usage: $${report.lines.reduce((sum, line) => sum + line.netAmount, 0).toFixed(2)}`);
12+
13+
console.log('\n=== Sync File Reading ===');
14+
const syncReport = await readGithubUsageReportFileSync('./tests/data/usageReport_1_0b650fc20d564ed2bddf337ac27c7a57.csv');
15+
console.log(`Sync read complete: ${syncReport.lines.length} lines processed`);
16+
17+
} catch (error) {
18+
console.error('Error reading usage report:', error);
19+
}
20+
}
21+
22+
nodeExample();

examples/web-example.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Example usage for web environments
2+
import { readGithubUsageReport } from "github-usage-report";
3+
4+
// Simulate CSV data that might come from a file upload or API
5+
const csvData = `"formatted_date","product","sku","quantity","unit_type","applied_cost_per_quantity","gross_amount","discount_amount","net_amount","username","organization","repository_name","workflow_name","workflow_path","cost_center_name"
6+
"2025-05-01","actions","actions_linux","100","minutes","0.008","0.8","0","0.8","user1","myorg","repo1","CI",".github/workflows/ci.yml","development"
7+
"2025-05-02","actions","actions_linux","150","minutes","0.008","1.2","0.2","1.0","user2","myorg","repo2","Deploy",".github/workflows/deploy.yml","production"`;
8+
9+
async function example() {
10+
try {
11+
const report = await readGithubUsageReport(csvData);
12+
13+
console.log('=== GitHub Usage Report ===');
14+
console.log(`Report period: ${report.startDate.toDateString()} to ${report.endDate.toDateString()}`);
15+
console.log(`Total days: ${report.days}`);
16+
console.log(`Total usage lines: ${report.lines.length}`);
17+
18+
console.log('\n=== Usage Details ===');
19+
report.lines.forEach(line => {
20+
console.log(`${line.date.toDateString()}: ${line.product} - ${line.quantity} ${line.unitType} ($${line.netAmount}) - ${line.workflowName}`);
21+
});
22+
23+
// Calculate total cost
24+
const totalCost = report.lines.reduce((sum, line) => sum + line.netAmount, 0);
25+
console.log(`\nTotal cost: $${totalCost.toFixed(2)}`);
26+
} catch (error) {
27+
console.error('Error parsing usage report:', error);
28+
}
29+
}
30+
31+
example();

0 commit comments

Comments
 (0)