127 lines
3.9 KiB
C#
127 lines
3.9 KiB
C#
using GreenHome.Application;
|
|
using GreenHome.Domain;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace GreenHome.Infrastructure;
|
|
|
|
public sealed class AIQueryService : IAIQueryService
|
|
{
|
|
private readonly GreenHomeDbContext dbContext;
|
|
private readonly ILogger<AIQueryService> logger;
|
|
|
|
public AIQueryService(
|
|
GreenHomeDbContext dbContext,
|
|
ILogger<AIQueryService> logger)
|
|
{
|
|
this.dbContext = dbContext;
|
|
this.logger = logger;
|
|
}
|
|
|
|
public async Task<AIQuery> SaveQueryAsync(AIQuery query, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
dbContext.AIQueries.Add(query);
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
logger.LogInformation("AI query saved: {QueryId}, Tokens: {TotalTokens}",
|
|
query.Id, query.TotalTokens);
|
|
|
|
return query;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Error saving AI query");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async Task<List<AIQuery>> GetDeviceQueriesAsync(
|
|
int deviceId,
|
|
int take = 50,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return await dbContext.AIQueries
|
|
.Where(q => q.DeviceId == deviceId)
|
|
.OrderByDescending(q => q.CreatedAt)
|
|
.Take(take)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<List<AIQuery>> GetUserQueriesAsync(
|
|
int userId,
|
|
int take = 50,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return await dbContext.AIQueries
|
|
.Where(q => q.UserId == userId)
|
|
.OrderByDescending(q => q.CreatedAt)
|
|
.Take(take)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<int> GetDeviceTotalTokensAsync(
|
|
int deviceId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return await dbContext.AIQueries
|
|
.Where(q => q.DeviceId == deviceId)
|
|
.SumAsync(q => q.TotalTokens, cancellationToken);
|
|
}
|
|
|
|
public async Task<int> GetUserTotalTokensAsync(
|
|
int userId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return await dbContext.AIQueries
|
|
.Where(q => q.UserId == userId)
|
|
.SumAsync(q => q.TotalTokens, cancellationToken);
|
|
}
|
|
|
|
public async Task<List<AIQuery>> GetRecentQueriesAsync(
|
|
int take = 20,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return await dbContext.AIQueries
|
|
.Include(q => q.Device)
|
|
.Include(q => q.User)
|
|
.OrderByDescending(q => q.CreatedAt)
|
|
.Take(take)
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<AIQueryStats> GetStatsAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var today = DateTime.UtcNow.Date;
|
|
|
|
var allQueries = await dbContext.AIQueries
|
|
.Select(q => new
|
|
{
|
|
q.TotalTokens,
|
|
q.PromptTokens,
|
|
q.CompletionTokens,
|
|
q.ResponseTimeMs,
|
|
q.CreatedAt
|
|
})
|
|
.ToListAsync(cancellationToken);
|
|
|
|
var todayQueries = allQueries.Where(q => q.CreatedAt >= today).ToList();
|
|
|
|
return new AIQueryStats
|
|
{
|
|
TotalQueries = allQueries.Count,
|
|
TotalTokensUsed = allQueries.Sum(q => q.TotalTokens),
|
|
TotalPromptTokens = allQueries.Sum(q => q.PromptTokens),
|
|
TotalCompletionTokens = allQueries.Sum(q => q.CompletionTokens),
|
|
AverageResponseTimeMs = allQueries.Any()
|
|
? allQueries.Where(q => q.ResponseTimeMs.HasValue)
|
|
.Average(q => q.ResponseTimeMs ?? 0)
|
|
: 0,
|
|
TodayQueries = todayQueries.Count,
|
|
TodayTokens = todayQueries.Sum(q => q.TotalTokens)
|
|
};
|
|
}
|
|
}
|
|
|