8ac593d36f
Backend CI / build-and-test (push) Failing after 14m19s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Failing after 12m5s
Frontend CI / build-and-check (push) Failing after 17m58s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 10m11s
🚀 Create and publish a Docker image / Build & publish backend image (push) Failing after 11m3s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Failing after 14m58s
69 lines
2.8 KiB
C#
69 lines
2.8 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using UniVerse.Application.Interfaces;
|
|
using UniVerse.Domain.Enums;
|
|
using UniVerse.Infrastructure.Data;
|
|
|
|
namespace UniVerse.Infrastructure.Services;
|
|
|
|
public class LlmAnalysisService : ILlmAnalysisService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
private readonly ILlmClient _llm;
|
|
private readonly IGamificationService _gamification;
|
|
private readonly ILogger<LlmAnalysisService> _logger;
|
|
|
|
public LlmAnalysisService(AppDbContext db, ILlmClient llm,
|
|
IGamificationService gamification, ILogger<LlmAnalysisService> logger)
|
|
{
|
|
_db = db; _llm = llm; _gamification = gamification; _logger = logger;
|
|
}
|
|
|
|
public async Task AnalyzeReviewAsync(int reviewId)
|
|
{
|
|
var review = await _db.Reviews.Include(r => r.Lecture)
|
|
.FirstOrDefaultAsync(r => r.Id == reviewId);
|
|
if (review == null || review.LlmStatus != ReviewLlmStatus.Pending) return;
|
|
|
|
try
|
|
{
|
|
var context = $"Lecture: {review.Lecture?.Title}";
|
|
var result = await _llm.AnalyzeReviewAsync(review.Text ?? "", context);
|
|
|
|
review.QualityScore = result.QualityScore;
|
|
review.Sentiment = ParseSentiment(result.Sentiment);
|
|
review.LlmTags = result.Tags;
|
|
review.IsInformative = result.IsInformative;
|
|
review.LlmRawOutput = result.RawOutput;
|
|
review.LlmStatus = ReviewLlmStatus.Analyzed;
|
|
review.UpdatedAt = DateTime.UtcNow;
|
|
await _db.SaveChangesAsync();
|
|
|
|
if (result.IsInformative)
|
|
await _gamification.AwardCoinsAsync(review.UserId, 10,
|
|
CoinTransactionType.ReviewReward, reviewId: review.Id,
|
|
description: "Informative review reward");
|
|
|
|
await _gamification.CheckAndAwardAchievementsAsync(review.UserId);
|
|
_logger.LogInformation("Review {ReviewId} analyzed successfully", reviewId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to analyze review {ReviewId}, will retry later", reviewId);
|
|
}
|
|
}
|
|
|
|
private static ReviewSentiment ParseSentiment(string value)
|
|
{
|
|
var normalized = value.Trim().ToLowerInvariant();
|
|
return normalized switch
|
|
{
|
|
"positive" or "положительный" or "положительная" or "позитивный" or "позитивная" => ReviewSentiment.Positive,
|
|
"negative" or "отрицательный" or "отрицательная" or "негативный" or "негативная" => ReviewSentiment.Negative,
|
|
"neutral" or "нейтральный" or "нейтральная" => ReviewSentiment.Neutral,
|
|
_ when Enum.TryParse<ReviewSentiment>(value, true, out var sentiment) => sentiment,
|
|
_ => ReviewSentiment.Neutral
|
|
};
|
|
}
|
|
}
|