b6878e3b45
The frontend sends the active language code (currentLang()) with every match request. CvMatcherService injects a language instruction into the system prompt so the LLM returns summary, strengths, gaps, recommendations, and evidence in the correct language. The match result cache (CvMatchResults) now includes Language as part of the lookup key so Romanian and English results are stored and retrieved independently. Existing cached rows default to 'en'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90 lines
3.1 KiB
C#
90 lines
3.1 KiB
C#
using System.Text.Json;
|
|
using Api.Data;
|
|
using Api.Data.Entities;
|
|
using Api.Data.Repositories.Contracts;
|
|
using CvMatcher.Models.Responses;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Api.Data.Repositories;
|
|
|
|
public sealed class EfMatcherRepository : IMatcherRepository
|
|
{
|
|
private readonly CvMatcherDbContext _db;
|
|
private readonly ILogger<EfMatcherRepository> _logger;
|
|
|
|
public EfMatcherRepository(CvMatcherDbContext db, ILogger<EfMatcherRepository> logger)
|
|
{
|
|
_db = db;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task InitializeAsync(CancellationToken ct)
|
|
{
|
|
_logger.LogInformation("Ensuring CV matcher database schema exists using EF Core");
|
|
//await _db.Database.EnsureCreatedAsync(ct);
|
|
}
|
|
|
|
public async Task<JobMatchResponse?> GetMatchAsync(string cvDocumentId, string jobDocumentId, string language, CancellationToken ct)
|
|
{
|
|
var json = await _db.CvMatchResults
|
|
.AsNoTracking()
|
|
.Where(x => x.CvDocumentId == cvDocumentId && x.JobDocumentId == jobDocumentId && x.Language == language)
|
|
.Select(x => x.ResultJson)
|
|
.FirstOrDefaultAsync(ct);
|
|
|
|
if (string.IsNullOrWhiteSpace(json)) return null;
|
|
|
|
var result = JsonSerializer.Deserialize<JobMatchResponse>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
if (result is not null) result.Cached = true;
|
|
return result;
|
|
}
|
|
|
|
public async Task SaveMatchAsync(string cvDocumentId, string jobDocumentId, string language, JobMatchResponse response, CancellationToken ct)
|
|
{
|
|
var exists = await _db.CvMatchResults.AnyAsync(
|
|
x => x.CvDocumentId == cvDocumentId && x.JobDocumentId == jobDocumentId && x.Language == language,
|
|
ct);
|
|
|
|
if (exists) return;
|
|
|
|
_db.CvMatchResults.Add(new CvMatchResultEntity
|
|
{
|
|
Id = Guid.NewGuid().ToString("N"),
|
|
CvDocumentId = cvDocumentId,
|
|
JobDocumentId = jobDocumentId,
|
|
Language = language,
|
|
ResultJson = JsonSerializer.Serialize(response, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
|
|
Score = response.Score,
|
|
CreatedAt = DateTime.UtcNow
|
|
});
|
|
|
|
await _db.SaveChangesAsync(ct);
|
|
}
|
|
|
|
public async Task<string?> GetChatCompletionAsync(string cacheKey, CancellationToken ct)
|
|
{
|
|
return await _db.CvMatcherChatCache
|
|
.AsNoTracking()
|
|
.Where(x => x.CacheKey == cacheKey)
|
|
.Select(x => x.ResponseText)
|
|
.FirstOrDefaultAsync(ct);
|
|
}
|
|
|
|
public async Task SaveChatCompletionAsync(string cacheKey, string model, decimal temperature, string responseText, CancellationToken ct)
|
|
{
|
|
var exists = await _db.CvMatcherChatCache.AnyAsync(x => x.CacheKey == cacheKey, ct);
|
|
if (exists) return;
|
|
|
|
_db.CvMatcherChatCache.Add(new CvMatcherChatCacheEntity
|
|
{
|
|
CacheKey = cacheKey,
|
|
Model = model,
|
|
Temperature = temperature,
|
|
ResponseText = responseText,
|
|
CreatedAt = DateTime.UtcNow
|
|
});
|
|
|
|
await _db.SaveChangesAsync(ct);
|
|
}
|
|
}
|