mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-26 07:06:08 +00:00
refactor: generalize handling of costly services
Usage/cost tracking per user was over-fitted to LLM/AI services. This commit adds CostService and updates AIChatService to use that instead of updating the `ai_usage` table. The `ai_usage` table is now considered deprecated. A service called PermissiveCreditService is enabled by default in SelfHostedModule. This is so users who host their own Puter instances don't have to worry about usage limits, since they're providing their own keys anyway.
This commit is contained in:
@@ -293,6 +293,9 @@ const install = async ({ services, app, useapi, modapi }) => {
|
||||
const { DevTODService } = require('./services/DevTODService');
|
||||
services.registerService('__dev-tod', DevTODService);
|
||||
|
||||
const { CostService } = require("./services/drivers/CostService");
|
||||
services.registerService('cost', CostService);
|
||||
|
||||
const { DriverService } = require("./services/drivers/DriverService");
|
||||
services.registerService('driver', DriverService);
|
||||
|
||||
|
||||
@@ -128,8 +128,9 @@ class AIChatService extends BaseService {
|
||||
this.log.noticeme('COST INFO', values);
|
||||
|
||||
|
||||
await this.db.insert('ai_usage', values);
|
||||
|
||||
const svc_cost = this.services.get('cost');
|
||||
svc_cost.record_cost({ cost: values.cost });
|
||||
|
||||
// USD cost from microcents
|
||||
const cost_usc = values.cost / 1000000;
|
||||
const cost_usd = cost_usc / 100;
|
||||
@@ -404,11 +405,8 @@ class AIChatService extends BaseService {
|
||||
});
|
||||
|
||||
// Updated: Check usage and get a boolean result instead of throwing error
|
||||
const usageAllowed = await this.check_usage_({
|
||||
actor: Context.get('actor'),
|
||||
service: service_used,
|
||||
model: model_used,
|
||||
});
|
||||
const svc_cost = this.services.get('cost');
|
||||
const usageAllowed = await svc_cost.get_funding_allowed();
|
||||
|
||||
// Handle usage limits reached case
|
||||
if ( !usageAllowed ) {
|
||||
@@ -496,11 +494,8 @@ class AIChatService extends BaseService {
|
||||
});
|
||||
|
||||
// Check usage for fallback model too (with updated method)
|
||||
const fallbackUsageAllowed = await this.check_usage_({
|
||||
actor: Context.get('actor'),
|
||||
service: fallback_service_name,
|
||||
model: fallback_model_name,
|
||||
});
|
||||
const svc_cost = this.services.get('cost');
|
||||
const fallbackUsageAllowed = await svc_cost.get_funding_allowed();
|
||||
|
||||
// If usage not allowed for fallback, use usage-limited-chat instead
|
||||
if (!fallbackUsageAllowed) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
const BaseService = require("../../services/BaseService");
|
||||
|
||||
/**
|
||||
* PermissiveCreditService listens to the event where DriverService asks
|
||||
* for a credit context, and always provides one that allows use of
|
||||
* cost-incurring services for no charge. This grants free use to
|
||||
* everyone to services that incur a cost, as long as the user has
|
||||
* permission to call the respective service.
|
||||
*/
|
||||
class PermissiveCreditService extends BaseService {
|
||||
static MODULES = {
|
||||
uuidv4: require('uuid').v4,
|
||||
}
|
||||
_init () {
|
||||
const svc_event = this.services.get('event');
|
||||
svc_event.on(`credit.check-available`, (_, event) => {
|
||||
event.available = Number.MAX_SAFE_INTEGER;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PermissiveCreditService;
|
||||
@@ -35,6 +35,9 @@ class SelfHostedModule extends AdvancedBase {
|
||||
const DevWatcherService = require('./DevWatcherService');
|
||||
const path_ = require('path');
|
||||
|
||||
const PermissiveCreditService = require("./PermissiveCreditService");
|
||||
services.registerService('__permissive-credit', PermissiveCreditService);
|
||||
|
||||
const { DBKVService } = require("../../services/DBKVService");
|
||||
services.registerService('puter-kvstore', DBKVService);
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
const APIError = require("../../api/APIError");
|
||||
const { Context } = require("../../util/context");
|
||||
const BaseService = require("../BaseService");
|
||||
|
||||
class CreditContext {
|
||||
constructor (svc, o) {
|
||||
for ( const k in o ) this[k] = o[k];
|
||||
this.svc = svc;
|
||||
}
|
||||
}
|
||||
|
||||
class CostService extends BaseService {
|
||||
static MODULES = {
|
||||
uuidv4: require('uuid').v4,
|
||||
}
|
||||
|
||||
_init () {
|
||||
const svc_cost = this;
|
||||
const svc_event = this.services.get('event');
|
||||
svc_event.on('driver.create-call-context', async (_, event) => {
|
||||
event.context = event.context.sub({
|
||||
// Future Use
|
||||
});
|
||||
});
|
||||
}
|
||||
async get_credit_context (params) {
|
||||
return new CreditContext(this, params);
|
||||
}
|
||||
|
||||
async get_funding_allowed () {
|
||||
const cost_uuid = this.modules.uuidv4();
|
||||
const svc_event = this.services.get('event');
|
||||
const event = {
|
||||
actor: Context.get('actor'),
|
||||
available: 0,
|
||||
cost_uuid,
|
||||
};
|
||||
await svc_event.emit('credit.check-available', event);
|
||||
return event.available > 0;
|
||||
}
|
||||
async record_cost ({ cost }) {
|
||||
const svc_event = this.services.get('event');
|
||||
const event = {
|
||||
actor: Context.get('actor'),
|
||||
cost,
|
||||
};
|
||||
await svc_event.emit('credit.record-cost', event);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
CostService,
|
||||
};
|
||||
@@ -268,9 +268,20 @@ class DriverService extends BaseService {
|
||||
skip_usage = true;
|
||||
}
|
||||
|
||||
return await Context.sub({
|
||||
const svc_event = this.services.get('event');
|
||||
const event = {};
|
||||
event.context = Context.sub({
|
||||
client_driver_call,
|
||||
}).arun(async () => {
|
||||
});
|
||||
event.call_details = {
|
||||
service: driver,
|
||||
iface, method, args,
|
||||
skip_usage,
|
||||
};
|
||||
|
||||
svc_event.emit('driver.create-call-context', event);
|
||||
|
||||
return event.context.arun(async () => {
|
||||
const result = await this.call_new_({
|
||||
actor,
|
||||
service,
|
||||
|
||||
Reference in New Issue
Block a user