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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2942349a31ca24bfb080791b3dba9bcb36eaf6fc9709718fe989e65c968ee489
4
- data.tar.gz: 57459071b36f2873e5dedf5f4c4d9d98bd1327527edeca2ff9c7bfaff7c14098
3
+ metadata.gz: f11a0fd8aa29a664ab72f45aa1516974dde22505c9e8f060ca8a051f0558de92
4
+ data.tar.gz: ad7a682ba71c648dba5dd12d6f47df0cd3ec9fc2590579e8a14bae4e1dd71e5c
5
5
  SHA512:
6
- metadata.gz: 961ca4017ed1159fb13920d86a07ad4ca78b7bea40f2d105893bdc57653a3deed4164c047b858c0cb5a779419deebd0cdc0a1f0e65d87dab232052b27558f44f
7
- data.tar.gz: 3c538fda52c54f226498c6f845d84f7fdd0e42ee78c582062a42fd529d54946ecb10ea470cc2ec7a59a68648358c7d454fbe771661454107f25d21e7a600a436
6
+ metadata.gz: '002058380aa56c5dfde8490cf908f019da6cb752774f6eef197c4c5746b4b5ce99fa45e76eefc0e596a5c19a5f3eee3ea811b04cbf85fb095a024db8ff08a365'
7
+ data.tar.gz: 9dc836d59bbda52b9974f98aae37da47eafbbe1581e8f260ef5bbe45de5ccb885148865cf0d787c01aa4ae84a0425d6f043aa8d3801a8e95058113c854c5fa64
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # OpenRouterUsageTracker
2
- [![Gem Version](https://badge.fury.io/rb/open_router_usage_tracker.svg)](https://badge.fury.io/rb/open_router_usage_tracker)
3
2
  [![Build Status](https://github.com/mclpio/open_router_usage_tracker/actions/workflows/ci.yml/badge.svg)](https://github.com/mclpio/open_router_usage_tracker/actions)
3
+ [![Gem Version](https://badge.fury.io/rb/open_router_usage_tracker.svg)](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.io](https://openrouter.ai/), enabling easy rate-limiting and monitoring for your users.
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
- $ bundle
19
+ bundle
20
20
  ```
21
21
 
22
22
  Or install it yourself as:
23
23
  ```bash
24
- $ gem install open_router_usage_tracker
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
- 1. **Run the Database Migration**:
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
- 1. **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`).
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 Usage
69
- The `Trackable` concern adds powerful querying methods to your user model.
73
+ ### Daily Usage Tracking and Rate-Limiting (Recommended)
70
74
 
71
- The main method is `usage_in_period(range)`, which returns a hash containing the total tokens and cost for a given time range.
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
- **Example: Implementing a rate limit**
77
+ The primary method is `cost_exceeded?(limit:)`, which provides a near-instantaneous check against a user's daily spending.
74
78
 
75
- Imagine you want to prevent users from using more than 100,000 tokens in a 24-hour period.
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 check_usage_limit
81
- usage = current_user.usage_in_last_24_hours
82
-
83
- if usage[:tokens] > 100_000
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
- The gem also provides `usage_in_last_24_hours` as a convenience method and you can always get all the data using `usage_logs`.
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
@@ -1,3 +1,3 @@
1
1
  module OpenRouterUsageTracker
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  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.1.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: This gem is your rocket launch to managing you web app's LLM usage and
27
- rate limiting users with built in methods!
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