134aac7bcf
Add a content-free usage ledger with legacy backfill. Reserve Workspace and durable Strategy/CV work before execution so deleted history or duplicate admission cannot reset limits.
54 lines
2.1 KiB
C#
54 lines
2.1 KiB
C#
using JobTrackerApi.Data;
|
|
using JobTrackerApi.Models;
|
|
using JobTrackerApi.Services;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace JobTrackerApi.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/ai/usage")]
|
|
[Authorize(AuthenticationSchemes = "local")]
|
|
public sealed class AiUsageController : ControllerBase
|
|
{
|
|
private readonly UserManager<ApplicationUser> _users;
|
|
private readonly JobTrackerContext _db;
|
|
private readonly AiUsageMeter? _usage;
|
|
|
|
public AiUsageController(UserManager<ApplicationUser> users, JobTrackerContext db, AiUsageMeter? usage = null)
|
|
{
|
|
_users = users;
|
|
_db = db;
|
|
_usage = usage;
|
|
}
|
|
|
|
public sealed record UsagePeriodDto(int Calls, long InputCharacters, long OutputCharacters, long EstimatedTokens);
|
|
public sealed record UsageDto(UsagePeriodDto CurrentMonth, UsagePeriodDto AllTime, string Plan, int MonthlyCallLimit, long MonthlyTokenLimit, long StorageUsedBytes, long StorageLimitBytes);
|
|
|
|
[HttpGet]
|
|
public async Task<ActionResult<UsageDto>> Get(CancellationToken cancellationToken)
|
|
{
|
|
var user = await _users.GetUserAsync(User);
|
|
if (user is null) return Unauthorized();
|
|
|
|
var roles = await _users.GetRolesAsync(user);
|
|
var entitlements = AccountPlans.ForRoles(roles);
|
|
var meter = _usage ?? new AiUsageMeter(_db, TimeProvider.System);
|
|
var currentMonth = ToDto(await meter.CurrentMonthAsync(user.Id, cancellationToken));
|
|
return Ok(new UsageDto(
|
|
currentMonth,
|
|
ToDto(await meter.AllTimeAsync(user.Id, cancellationToken)),
|
|
AccountPlans.Name(entitlements),
|
|
entitlements.MonthlyAiCalls,
|
|
entitlements.MonthlyAiTokens,
|
|
await _db.Attachments.Where(x => x.JobApplication.OwnerUserId == user.Id)
|
|
.SumAsync(x => (long?)x.FileSize, cancellationToken) ?? 0,
|
|
entitlements.StorageBytes));
|
|
}
|
|
|
|
private static UsagePeriodDto ToDto(AiUsageTotals totals)
|
|
=> new(totals.Calls, totals.InputCharacters, totals.OutputCharacters, totals.EstimatedTokens);
|
|
}
|