mirror of
https://github.com/HeyPuter/puter.git
synced 2026-02-26 20:09:34 -06:00
dev: add usage check hook for ai services
This commit is contained in:
@@ -365,6 +365,11 @@ module.exports = class APIError {
|
||||
message: ({ method_key, limit }) =>
|
||||
`Monthly limit exceeded for method ${quot(method_key)}: ${limit} requests per month.`,
|
||||
},
|
||||
'monthly_usage_exceeded': {
|
||||
status: 429,
|
||||
message: ({ limit, unit }) =>
|
||||
`Monthly limit exceeded: ${limit} ${unit} per month.`,
|
||||
},
|
||||
'server_rate_exceeded': {
|
||||
status: 503,
|
||||
message: 'System-wide rate limit exceeded. Please try again later.',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const APIError = require("../../api/APIError");
|
||||
const { PermissionUtil } = require("../../services/auth/PermissionService");
|
||||
const BaseService = require("../../services/BaseService");
|
||||
const { DB_WRITE } = require("../../services/database/consts");
|
||||
const { TypeSpec } = require("../../services/drivers/meta/Construct");
|
||||
@@ -28,7 +30,7 @@ class AIChatService extends BaseService {
|
||||
svc_event.on('ai.prompt.report-usage', async (_, details) => {
|
||||
const values = {
|
||||
user_id: details.actor?.type?.user?.id,
|
||||
app_id: details.actor?.type?.app?.id,
|
||||
app_id: details.actor?.type?.app?.id ?? null,
|
||||
service_name: details.service_used,
|
||||
model_name: details.model_used,
|
||||
value_uint_1: details.usage?.input_tokens,
|
||||
@@ -196,6 +198,11 @@ class AIChatService extends BaseService {
|
||||
let ret, error, errors = [];
|
||||
let service_used = intended_service;
|
||||
let model_used = this.get_model_from_request(parameters);
|
||||
await this.check_usage_({
|
||||
actor: Context.get('actor'),
|
||||
service: service_used,
|
||||
model: model_used,
|
||||
});
|
||||
try {
|
||||
ret = await svc_driver.call_new_({
|
||||
actor: Context.get('actor'),
|
||||
@@ -239,6 +246,11 @@ class AIChatService extends BaseService {
|
||||
fallback_model_name
|
||||
});
|
||||
|
||||
await this.check_usage_({
|
||||
actor: Context.get('actor'),
|
||||
service: fallback_service_name,
|
||||
model: fallback_model_name,
|
||||
});
|
||||
try {
|
||||
ret = await svc_driver.call_new_({
|
||||
actor: Context.get('actor'),
|
||||
@@ -318,6 +330,35 @@ class AIChatService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
async check_usage_ ({ actor, service, model }) {
|
||||
const svc_permission = this.services.get('permission');
|
||||
const svc_event = this.services.get('event');
|
||||
const reading = await svc_permission.scan(actor, `paid-services:ai-chat`);
|
||||
const options = PermissionUtil.reading_to_options(reading);
|
||||
|
||||
// Query current ai usage in terms of cost
|
||||
const [row] = await this.db.read(
|
||||
'SELECT SUM(`cost`) AS sum FROM `ai_usage` ' +
|
||||
'WHERE `user_id` = ?',
|
||||
[actor.type.user.id]
|
||||
);
|
||||
|
||||
const cost_used = row?.sum || 0;
|
||||
|
||||
const event = {
|
||||
allowed: true,
|
||||
actor,
|
||||
service, model,
|
||||
cost_used,
|
||||
permission_options: options,
|
||||
};
|
||||
await svc_event.emit('ai.prompt.check-usage', event);
|
||||
if ( event.error ) throw event.error;
|
||||
if ( ! event.allowed ) {
|
||||
throw new APIError('forbidden');
|
||||
}
|
||||
}
|
||||
|
||||
async moderate ({ messages }) {
|
||||
const svc_openai = this.services.get('openai-completion');
|
||||
|
||||
|
||||
@@ -44,7 +44,15 @@ module.exports = eggspress('/drivers/usage', {
|
||||
user: {}, // map[str(iface:method)]{date,count,max}
|
||||
apps: {}, // []{app,map[str(iface:method)]{date,count,max}}
|
||||
app_objects: {},
|
||||
usages: [],
|
||||
};
|
||||
|
||||
const event = {
|
||||
usages: [],
|
||||
};
|
||||
const svc_event = x.get('services').get('event');
|
||||
await svc_event.emit('usages.query', event);
|
||||
usages.usages = event.usages;
|
||||
|
||||
const rows = await db.read(
|
||||
'SELECT * FROM `service_usage_monthly` WHERE user_id=? ' +
|
||||
@@ -184,5 +192,6 @@ module.exports = eggspress('/drivers/usage', {
|
||||
user: Object.values(usages.user),
|
||||
apps: usages.apps,
|
||||
app_objects: usages.app_objects,
|
||||
usages: usages.usages,
|
||||
});
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user