Accounting for AI Usage
As AI usage relies on paid APIs, providers may want to charge their users for AI usage. The service supports a flexible way to apply different commercial models. This is done by counting API requests per user. When enabled, the Accounting feature ensures that all requests done by a user are counted in a database. This number is checked against a so called "plan" which is assigned to the user. If the AI quota is reached, no additional request can be made for the current time range.
For instance, a "free" plan might allow 10 requests per day or month, while a paid plan allows 1000 requests per month. The user and brand limits can be configured via config map on the Helm chart. A plan is an object with its key as the id
for the plan and has the following properties:
name
: The name of the planplan
: The type of the plan (free, paid)strategy
: The strategy for the plan (duration, monthly)duration
: The duration if strategy is "duration" (format is30d
for 30 days)limit
: The limit of requests per user and brandenabled
: The plan is enabled or not
Additional Strategies Explanation
The monthly
strategy resets usage at the start of each new month, providing a monthly quota of requests.
The duration
strategy uses a fixed number of days (e.g., 14 days) and a certain request limit. Once the trial period ends or the quota is reached, the service returns 402 Payment Required, preventing further use. This prevents abuse of trial accounts and differentiates them from longer-term or recurring monthly plans.
Activation
To activate the Accounting feature in a Kubernetes environment, modify the configuration file by setting the accounting.enabled
value to true
in your values file.
When enabled, it monitors user activity and enforces quotas according to the user's capabilities and associated plan.
Functionality
Once the Accounting feature is activated, the service will inspect each user's JSON Web Token (JWT) for specific "capabilities" that match a configured "plan."
How It Works
JWT Inspection: When a user makes a request, the service inspects the user's JWT for any "capabilities" that correspond to a configured plan.
Plan Matching: If a capability matches a predefined plan, the service begins tracking the user's usage according to the rules of that plan.
Usage Tracking: The service monitors the number of requests made by the user as specified by the plan's quota. For example, a plan may allow 100 requests per month.
Quota Enforcement: If the user reaches the quota limit (e.g., 100 requests per month), the service responds with a status code 402 Payment Required to indicate that the quota has been exhausted.
Default Plan: If no capability is found that matches a configured plan, the user is automatically assigned a default plan. The default plan allows up to 10,000 requests per month.
Response Codes
200 OK: Request was successful, and usage is within quota limits. The response will include information about the user's remaining quota. The responses body will contain the property
remainingRequests
with the number of remaining requests.402 Payment Required: The user has reached the quota limit for their plan.
User Routes
The service provides a route for users to check their usage and remaining quota:
GET /api/quotas
: Get the all quotas for the current user. The responses body will contain the arrayremainingRequests
of objects containing the servicename as key and the number of remaning requests as value.GET /api/quotas/:model
: Get the all quotas for the current user for the specific:model
. The responses body will contain the propertyremainingRequests
with the number of remaining requests.
Admin routes
There are several routes available for administrators to monitor usage and reset quotas:
GET /api/admin/brands/:brand/usage/:year/:month
: Get usage statistics for a specific brand in a given month.:brand
is the brand ID,:year
is the year, and:month
is the month. Example/api/admin/brands/brand1/usage/2024/1
GET /api/admin/quotas/:service/:cid
: Get the quota for a specific user and service.:service
is the name of the service (e.g.,openai
), and:cid
is the composite user ID which is a combination of the context ID and the numeric user ID. For example,:cid
could be1-123
.DELETE /api/admin/quotas/:service/:cid/:strategy
: Reset the quota for a specific user and service.:service
is the name of the service (e.g.,openai
),:cid
is the composite user ID, and:strategy
is the strategy for the plan (e.g.,monthly
orduration
).
To secure these routes, there are 3 options available for authentication:
Basic Auth: Use basic authentication with the
basicAuth.user
andbasicAuth.password
values in the configuration file. If you want to use the charts secret file you have to setbasicAuth.enabled
totrue
. Otherwise, you can provide your own secret withbasicAuth.enabled
set tofalse
andoverrides.basicAuth
set to the secret name. The provided secret should contain the keysbasic_auth_user
andbasic_auth_password
. In this case you don't need to setbasicAuth.user
andbasicAuth.password
. The request header should contain theAuthorization
header with the valueBasic base64(username:password)
.Bearer Auth: Use bearer authentication with the
bearerAuth.keys
value in the configuration file. ThebearerAuth.keys
value should be a list of keys that are allowed to access the admin routes seperated by a comma. If you want to use the charts secret file you have to setbearerAuth.enabled
totrue
. Otherwise, you can provide your own secret withbearerAuth.enabled
set tofalse
andoverrides.bearerAuth
set to the secret name. The provided secret should contain the keybearer_auth_keys
. In this case you don't need to setbearerAuth.keys
. The request header should contain theAuthorization
header with the valueBearer <key>
.OAuth2: Given that you have an OAuth2 server running and this server supports openid connect and JWKS, you can use the
oauth2.domain
configuration to secure the admin routes. Turn this on viaoauth2.enabled
set totrue
. The service will then discover the JWKS from the given domain and validate the JWTs with it. The request header should contain theAuthorization
header with the valueBearer <JWT>
.
Info
Take note that you can configure multiple authentication methods at the same time. The service will try to authenticate the request with the first method and if it fails, it will try the next one. If no auth is enabled (default), no admin route is exposed at all.
Example plan configuration:
plans:
- premium:
name: "AI Premium"
plan: "paid"
strategy: "monthly"
limit: 100
enabled: true
- trial:
name: "AI Trial"
plan: "free"
strategy: "duration"
duration: "30d"
limit: 25
enabled: true
- specialTrial:
name: "AI Sneak Peak Week"
plan: "free"
strategy: "duration"
limit: 7
limit: 15
enabled: true
How capabilities are matched to plans
The service will look for the capabilities
property in the JWT. If capabilities are found, the service will look for a capability that matches the ID of a plan (premium
, trial
, or specialTrial
, as in the example above). If a plan is found, the service will use the plan to track the user's usage. If no plan is found, the service will use the default plan (10,000 requests per month). If the user has more than one capability that matches a plan, the service will use the first one found and log a warning.
How to set the capabilities in the JWT
The capabilities are set in the JWT by the Switchboard. The Switchboard will check for all App Suite capabilities of a user, then apply a filter so that only relevant capabilities are added to the JWT. This means you need to set the desired capability, for example, specialTrial
, on the App Suite side for your user. This will most likely be handled by your upsell code, your administrators via the SOAP API, or the config cascade.
Once the user has the correct capability, the Switchboard needs to be configured to add the capability to the JWT. This is done by adding your capability to the Switchboard’s jwt.serviceCapabilities
value, which by default is set to "switchboard,openai,zoom,jitsi"
(be sure to add your capability rather than overwriting the defaults, e.g., "switchboard,openai,zoom,jitsi,specialTrial"
). See the Switchboard documentation. This list acts like an allowlist for the user's capabilities. If the user has the capability, it will be added to the JWT.
Steps to Configure the AI Service
Fill out Database Configuration
Add the following configuration to enable the database for the AI service:
database: host: <your mysql host> name: <your db name> user: <your mysql user omit if you provide your own secret> password: <password of your mysql user omit if you provide your own secret>
Optional: Custom Database Secret
If you want to use your own secret for the database, set the
mysqlSecret.enabled
tofalse
and provide the secret name inoverrides.mysqlSecret
.Prepare the Database
The service expects an existing database to connect to and run initial migrations. Follow the steps below to set up the database correctly.
Database Schema Setup
To ensure the AI service operates correctly, you need to create the necessary tables and procedures in your database. Although the actual migration script will be executed automatically, it is essential to ensure that the database user has the appropriate permissions.
Minimal Required Grants
The minimal grants needed for the database user are:
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER
ON `your_database_name`.*
TO 'your_db_user'@'%';
Replace your_database_name
with the name of your database and your_db_user
with the name of your database user.
Example Configuration
Here's an example of how to grant the necessary permissions:
CREATE USER 'ai_service_user'@'%' IDENTIFIED BY 'secure_password';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER
ON `ai_service_db`.*
TO 'ai_service_user'@'%';
FLUSH PRIVILEGES;
In this example:
ai_service_user
is the database user for the AI service.secure_password
is the password for the database user.ai_service_db
is the database name for the AI service.