open_router_usage_tracker 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +50 -18
- data/app/models/concerns/open_router_usage_tracker/trackable.rb +14 -0
- data/app/models/open_router_usage_tracker/daily_summary.rb +11 -0
- data/lib/generators/open_router_usage_tracker/summary_install/summary_install_generator.rb +19 -0
- data/lib/generators/open_router_usage_tracker/summary_install/templates/migration.rb +13 -0
- data/lib/open_router_usage_tracker/version.rb +1 -1
- data/lib/open_router_usage_tracker.rb +20 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f11a0fd8aa29a664ab72f45aa1516974dde22505c9e8f060ca8a051f0558de92
|
4
|
+
data.tar.gz: ad7a682ba71c648dba5dd12d6f47df0cd3ec9fc2590579e8a14bae4e1dd71e5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '002058380aa56c5dfde8490cf908f019da6cb752774f6eef197c4c5746b4b5ce99fa45e76eefc0e596a5c19a5f3eee3ea811b04cbf85fb095a024db8ff08a365'
|
7
|
+
data.tar.gz: 9dc836d59bbda52b9974f98aae37da47eafbbe1581e8f260ef5bbe45de5ccb885148865cf0d787c01aa4ae84a0425d6f043aa8d3801a8e95058113c854c5fa64
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# OpenRouterUsageTracker
|
2
|
-
[](https://badge.fury.io/rb/open_router_usage_tracker)
|
3
2
|
[](https://github.com/mclpio/open_router_usage_tracker/actions)
|
3
|
+
[](https://badge.fury.io/rb/open_router_usage_tracker)
|
4
4
|
|
5
|
-
An effortless Rails engine to track API token usage and cost from [OpenRouter
|
5
|
+
An effortless Rails engine to track API token usage and cost from [OpenRouter](https://openrouter.ai/), enabling easy rate-limiting and monitoring for your users.
|
6
6
|
|
7
7
|
## Motivation
|
8
8
|
Managing Large Language Model (LLM) API costs is crucial for any application that provides AI features to users. This gem provides simple, out-of-the-box tools to log every OpenRouter API call, associate it with a user, and query their usage over time. This allows you to easily implement spending caps, rate limits, or usage-based billing tiers.
|
@@ -16,27 +16,32 @@ gem "open_router_usage_tracker"
|
|
16
16
|
|
17
17
|
And then execute:
|
18
18
|
```bash
|
19
|
-
|
19
|
+
bundle
|
20
20
|
```
|
21
21
|
|
22
22
|
Or install it yourself as:
|
23
23
|
```bash
|
24
|
-
|
24
|
+
gem install open_router_usage_tracker
|
25
25
|
```
|
26
26
|
|
27
27
|
## Setup
|
28
28
|
|
29
|
-
1. **Run the Install Generator**: This will create a migration file in your application to add the open_router_usage_logs table.
|
29
|
+
1. **Run the Install Generator**: This will create a migration file in your application to add the `open_router_usage_logs` table.
|
30
30
|
```bash
|
31
31
|
bin/rails g open_router_usage_tracker:install
|
32
32
|
```
|
33
33
|
|
34
|
-
|
34
|
+
2. **Run the Summary Table Generator (New in v0.2.0)**: To enable performant daily rate-limiting, generate the migration for the summary table.
|
35
|
+
```bash
|
36
|
+
bin/rails g open_router_usage_tracker:summary_install
|
37
|
+
```
|
38
|
+
|
39
|
+
3. **Run the Database Migrations**:
|
35
40
|
```bash
|
36
41
|
bin/rails db:migrate
|
37
42
|
```
|
38
43
|
|
39
|
-
|
44
|
+
4. **Include the `Trackable` Concern**: To add the usage tracking methods (`usage_in_period`, etc.) to your user model, include the concern. This works with any user-like model (e.g., `User`, `Account`).
|
40
45
|
```ruby
|
41
46
|
# app/models/user.rb
|
42
47
|
class User < ApplicationRecord
|
@@ -65,29 +70,56 @@ rescue ActiveRecord::RecordInvalid => e
|
|
65
70
|
end
|
66
71
|
```
|
67
72
|
|
68
|
-
### Tracking
|
69
|
-
The `Trackable` concern adds powerful querying methods to your user model.
|
73
|
+
### Daily Usage Tracking and Rate-Limiting (Recommended)
|
70
74
|
|
71
|
-
|
75
|
+
For high-performance rate-limiting, the gem provides helpers that query a daily summary table. This avoids slow `SUM` queries on the main log table.
|
72
76
|
|
73
|
-
|
77
|
+
The primary method is `cost_exceeded?(limit:)`, which provides a near-instantaneous check against a user's daily spending.
|
74
78
|
|
75
|
-
|
79
|
+
**Example: Implementing a daily cost limit**
|
80
|
+
|
81
|
+
Imagine you want to prevent users from spending more than $1.00 per day.
|
76
82
|
|
77
83
|
```ruby
|
78
84
|
# somewhere in a controller or before_action
|
79
85
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
render json: { error: "You have exceeded your daily usage limit." }, status: :too_many_requests
|
86
|
+
def enforce_daily_limit
|
87
|
+
# This check is extremely fast as it queries the small summary table.
|
88
|
+
if current_user.cost_exceeded?(limit: 1.00)
|
89
|
+
render json: { error: "You have exceeded your daily spending limit." }, status: :too_many_requests
|
85
90
|
return
|
86
91
|
end
|
87
92
|
end
|
88
93
|
```
|
89
94
|
|
90
|
-
|
95
|
+
You can also retrieve the full summary for the current day (UTC):
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
summary = current_user.usage_today
|
99
|
+
# => <OpenRouterUsageTracker::DailySummary id: 1, user_id: 1, day: "2025-06-28", total_tokens: 1500, cost: 0.025, ...>
|
100
|
+
|
101
|
+
summary.cost
|
102
|
+
# => 0.025
|
103
|
+
|
104
|
+
summary.total_tokens
|
105
|
+
# => 1500
|
106
|
+
```
|
107
|
+
|
108
|
+
### Historical Usage Tracking
|
109
|
+
|
110
|
+
The `Trackable` concern also adds methods for querying historical usage from the main log table.
|
111
|
+
|
112
|
+
The main method is `usage_in_period(range)`, which returns a hash containing the total tokens and cost for a given time range.
|
113
|
+
|
114
|
+
**Example: Checking usage for the current month**
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
range = Time.current.beginning_of_month..Time.current
|
118
|
+
usage = current_user.usage_in_period(range)
|
119
|
+
# => { tokens: 50000, cost: 1.25 }
|
120
|
+
```
|
121
|
+
|
122
|
+
**DEPRECATED for rate-limiting**: The `usage_in_last_24_hours` method is still available but is **not recommended** for implementing rate limits due to its performance implications. Use `cost_exceeded?` instead for a more robust and scalable solution.
|
91
123
|
|
92
124
|
## Contributing
|
93
125
|
Open an issue first.
|
@@ -6,6 +6,20 @@ module OpenRouterUsageTracker
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
has_many :usage_logs, as: :user, class_name: "OpenRouterUsageTracker::UsageLog", dependent: :destroy
|
9
|
+
has_many :daily_summaries, as: :user, class_name: "OpenRouterUsageTracker::DailySummary", dependent: :destroy
|
10
|
+
end
|
11
|
+
|
12
|
+
def usage_today
|
13
|
+
daily_summaries.find_by(day: Date.current)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cost_exceeded?(limit:, period: :daily)
|
17
|
+
case period
|
18
|
+
when :daily
|
19
|
+
usage_today&.cost.to_d > limit
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Unsupported period: #{period}"
|
22
|
+
end
|
9
23
|
end
|
10
24
|
|
11
25
|
# A flexible method to query usage within any time period.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module OpenRouterUsageTracker
|
2
|
+
class DailySummary < ApplicationRecord
|
3
|
+
self.table_name = "open_router_daily_summaries"
|
4
|
+
|
5
|
+
belongs_to :user, polymorphic: true
|
6
|
+
|
7
|
+
validates :day, presence: true
|
8
|
+
validates :total_tokens, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
9
|
+
validates :cost, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
module OpenRouterUsageTracker
|
4
|
+
module Generators
|
5
|
+
class SummaryInstallGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def self.next_migration_number(dir)
|
11
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_migration_file
|
15
|
+
migration_template "migration.rb", "db/migrate/create_open_router_daily_summaries.rb"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateOpenRouterDailySummaries < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :open_router_daily_summaries do |t|
|
4
|
+
t.references :user, null: false, polymorphic: true
|
5
|
+
t.date :day, null: false
|
6
|
+
t.integer :total_tokens, null: false, default: 0
|
7
|
+
t.decimal :cost, precision: 10, scale: 5, null: false, default: 0.0
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :open_router_daily_summaries, [ :user_type, :user_id, :day ], unique: true, name: "index_daily_summaries_on_user_and_day"
|
12
|
+
end
|
13
|
+
end
|
@@ -7,6 +7,16 @@ module OpenRouterUsageTracker
|
|
7
7
|
attr_writer :configuration
|
8
8
|
|
9
9
|
def log(response:, user:)
|
10
|
+
ApplicationRecord.transaction do
|
11
|
+
usage_log = create_usage_log(response, user)
|
12
|
+
update_daily_summary(usage_log)
|
13
|
+
usage_log
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def create_usage_log(response, user)
|
10
20
|
attributes = {
|
11
21
|
model: response["model"],
|
12
22
|
prompt_tokens: response.dig("usage", "prompt_tokens"),
|
@@ -17,8 +27,17 @@ module OpenRouterUsageTracker
|
|
17
27
|
raw_usage_response: response,
|
18
28
|
user: user
|
19
29
|
}
|
20
|
-
|
21
30
|
OpenRouterUsageTracker::UsageLog.create!(attributes)
|
22
31
|
end
|
32
|
+
|
33
|
+
def update_daily_summary(usage_log)
|
34
|
+
summary = OpenRouterUsageTracker::DailySummary.find_or_initialize_by(
|
35
|
+
user: usage_log.user,
|
36
|
+
day: Date.current
|
37
|
+
)
|
38
|
+
summary.total_tokens += usage_log.total_tokens
|
39
|
+
summary.cost += usage_log.cost
|
40
|
+
summary.save!
|
41
|
+
end
|
23
42
|
end
|
24
43
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: open_router_usage_tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MclPio
|
@@ -23,8 +23,8 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: 8.0.2
|
26
|
-
description:
|
27
|
-
|
26
|
+
description: A simple Rails engine to log OpenRouter API usage and provide methods
|
27
|
+
for tracking user consumption over time, enabling easy rate-limiting.
|
28
28
|
email:
|
29
29
|
- mclpious@gmail.com
|
30
30
|
executables: []
|
@@ -35,9 +35,12 @@ files:
|
|
35
35
|
- README.md
|
36
36
|
- Rakefile
|
37
37
|
- app/models/concerns/open_router_usage_tracker/trackable.rb
|
38
|
+
- app/models/open_router_usage_tracker/daily_summary.rb
|
38
39
|
- app/models/open_router_usage_tracker/usage_log.rb
|
39
40
|
- lib/generators/open_router_usage_tracker/install/install_generator.rb
|
40
41
|
- lib/generators/open_router_usage_tracker/install/templates/migration.rb
|
42
|
+
- lib/generators/open_router_usage_tracker/summary_install/summary_install_generator.rb
|
43
|
+
- lib/generators/open_router_usage_tracker/summary_install/templates/migration.rb
|
41
44
|
- lib/open_router_usage_tracker.rb
|
42
45
|
- lib/open_router_usage_tracker/engine.rb
|
43
46
|
- lib/open_router_usage_tracker/railtie.rb
|