feat(cv-matcher): add AiPrompts table; remove MyAiDbContext dependency
cv-matcher-data: - Add AiPromptEntity (Key, Language, Value, Description, UpdatedAt) - Add AiPrompts DbSet to CvMatcherDbContext with composite PK - Migration AddAiPrompts: create cvMatcher.AiPrompts table and seed ai.cv-match.system-prompt (language "*") with the current prompt value cv-matcher-api: - Add IAiPromptsRepository / EfAiPromptsRepository under Data/Repositories/ - CvMatcherService: inject IAiPromptsRepository; replace _templates.Render(...) with async DB lookup + simple string replacement - Program.cs: register IAiPromptsRepository (scoped); remove MyAiDbContext, ITemplateService/DbTemplateService registrations and MyAiDbContext migration call - Remove myai-data ProjectReference Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace CvMatcher.Data.Repositories.Contracts;
|
||||
|
||||
public interface IAiPromptsRepository
|
||||
{
|
||||
Task<string?> GetAsync(string key, string language, CancellationToken ct);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using CvMatcher.Data;
|
||||
using CvMatcher.Data.Repositories.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CvMatcher.Data.Repositories;
|
||||
|
||||
public sealed class EfAiPromptsRepository : IAiPromptsRepository
|
||||
{
|
||||
private readonly CvMatcherDbContext _db;
|
||||
|
||||
public EfAiPromptsRepository(CvMatcherDbContext db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<string?> GetAsync(string key, string language, CancellationToken ct)
|
||||
{
|
||||
return await _db.AiPrompts
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Key == key && x.Language == language)
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@ using Api.Services.Contracts;
|
||||
using CvMatcher.Models.Settings;
|
||||
using CvSearch.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MyAi.Data;
|
||||
using MyAi.Data.Services;
|
||||
using Refit;
|
||||
using Serilog;
|
||||
using Common.Settings;
|
||||
@@ -76,18 +74,8 @@ try
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddDbContext<MyAiDbContext>(options =>
|
||||
{
|
||||
var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration);
|
||||
options.UseSqlServer(connectionString, sql =>
|
||||
{
|
||||
sql.MigrationsAssembly("myai-data");
|
||||
sql.MigrationsHistoryTable(MyAiDbContext.MigrationTableName, MyAiDbContext.SchemaName);
|
||||
});
|
||||
});
|
||||
builder.Services.AddSingleton<ITemplateService, DbTemplateService>();
|
||||
|
||||
builder.Services.AddScoped<IMatcherRepository, EfMatcherRepository>();
|
||||
builder.Services.AddScoped<IAiPromptsRepository, EfAiPromptsRepository>();
|
||||
builder.Services.AddScoped<ICvMatcherService, CvMatcherService>();
|
||||
builder.Services.AddScoped<IJobTokenService, JobTokenService>();
|
||||
|
||||
@@ -122,11 +110,6 @@ try
|
||||
var db = scope.ServiceProvider.GetRequiredService<CvSearchDbContext>();
|
||||
db.Database.Migrate();
|
||||
}
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<MyAiDbContext>();
|
||||
db.Database.Migrate();
|
||||
}
|
||||
|
||||
Log.Information("{Service} startup complete", ServiceName);
|
||||
app.Run();
|
||||
|
||||
@@ -7,7 +7,6 @@ using CvMatcher.Models.Responses;
|
||||
using CvMatcher.Models.Settings;
|
||||
using Api.Services.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MyAi.Data.Services;
|
||||
|
||||
namespace Api.Services;
|
||||
|
||||
@@ -17,23 +16,23 @@ public sealed class CvMatcherService : ICvMatcherService
|
||||
private readonly IJobTextExtractor _jobTextExtractor;
|
||||
private readonly IMatcherAiClient _ai;
|
||||
private readonly IMatcherRepository _repository;
|
||||
private readonly IAiPromptsRepository _aiPrompts;
|
||||
private readonly MatcherSettings _settings;
|
||||
private readonly ITemplateService _templates;
|
||||
|
||||
public CvMatcherService(
|
||||
IRagApiClient rag,
|
||||
IJobTextExtractor jobTextExtractor,
|
||||
IMatcherAiClient ai,
|
||||
IMatcherRepository repository,
|
||||
IOptions<MatcherSettings> options,
|
||||
ITemplateService templates)
|
||||
IAiPromptsRepository aiPrompts,
|
||||
IOptions<MatcherSettings> options)
|
||||
{
|
||||
_rag = rag;
|
||||
_jobTextExtractor = jobTextExtractor;
|
||||
_ai = ai;
|
||||
_repository = repository;
|
||||
_aiPrompts = aiPrompts;
|
||||
_settings = options.Value;
|
||||
_templates = templates;
|
||||
}
|
||||
|
||||
public async Task<CvUploadResponse> UploadCvAsync(IFormFile file, CancellationToken ct)
|
||||
@@ -115,8 +114,9 @@ public sealed class CvMatcherService : ICvMatcherService
|
||||
var evidence = evidenceChunks.Count > 0 ? string.Join("\n\n", evidenceChunks.Take(4)) : Limit(job.Text, 4000);
|
||||
var languageName = LanguageName(language);
|
||||
|
||||
var systemPrompt = _templates.Render("ai.cv-match.system-prompt", "*",
|
||||
("languageName", languageName));
|
||||
var promptTemplate = await _aiPrompts.GetAsync("ai.cv-match.system-prompt", "*", ct)
|
||||
?? "You are a strict CV-to-job matching engine. Return JSON only.";
|
||||
var systemPrompt = promptTemplate.Replace("{{languageName}}", languageName, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var userPrompt = $"""
|
||||
CV:
|
||||
|
||||
@@ -83,6 +83,5 @@
|
||||
<ProjectReference Include="..\cv-matcher-data\cv-matcher-data.csproj" />
|
||||
<ProjectReference Include="..\common\common.csproj" />
|
||||
<ProjectReference Include="..\..\Helpers\startup-helpers\startup-helpers.csproj" />
|
||||
<ProjectReference Include="..\myai-data\myai-data.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user