Files
PaperlessAI/Services/DocumentProcessingService.cs
T
2026-10-12 01:14:13 +02:00

134 lines
4.3 KiB
C#

using System;
using System.Diagnostics.CodeAnalysis;
using PaperlessAI.Context;
using PaperlessAI.Enums;
using PaperlessAI.Models;
using PaperlessAI.Models.LMStudio;
using PaperlessAI.Repositories;
namespace PaperlessAI.Services;
public class DocumentProcessingService(IServiceScopeFactory scopeFactory, ILogger<DocumentProcessingService> logger)
{
private Queue<PaperlessDocument> paperlessDocumentsQueue = new Queue<PaperlessDocument>();
private bool isWorking = false;
public async Task Enqueue(List<PaperlessDocument> paperlessDocuments)
{
if(paperlessDocumentsQueue.Count != 0)
return;
foreach(var doc in paperlessDocuments)
{
await Enqueue(doc);
}
}
public async Task Enqueue(PaperlessDocument paperlessDocument)
{
if(paperlessDocumentsQueue.Contains(paperlessDocument, new PaperlessDocumentSameDocument()))
return;
await using var scope = scopeFactory.CreateAsyncScope();
var repository = scope.ServiceProvider.GetRequiredService<PaperlessDocumentRepository>();
paperlessDocumentsQueue.Enqueue(paperlessDocument);
paperlessDocument.SetDocumentState(EDocumentState.Enqueued);
await repository.Update(paperlessDocument);
logger.LogInformation($"Enqueued document: {paperlessDocument}");
}
public async Task Process()
{
if(isWorking)
return;
if(paperlessDocumentsQueue.Count == 0)
return;
if(paperlessDocumentsQueue.TryDequeue(out PaperlessDocument? docToProcess))
{
logger.LogInformation($"Dequeued: {docToProcess}");
var llmResponse = await ProcessDocument(docToProcess);
await UpdateDocumentData(docToProcess, llmResponse);
logger.LogInformation($"Document processed: {docToProcess} | Success: {llmResponse?.Success ?? false}");
}
if(paperlessDocumentsQueue.Count == 0)
{
await UnloadModel();
}
}
private async Task UpdateDocumentData(PaperlessDocument document, LmStudioLlmResponse llmResponse)
{
await using var scope = scopeFactory.CreateAsyncScope();
var repository = scope.ServiceProvider.GetRequiredService<PaperlessDocumentRepository>();
var isSameId = document.DocumentId == llmResponse?.DocumentId;
if(!llmResponse!.IsValid || !isSameId)
{
document.SetDocumentState(EDocumentState.Failed);
document.SetLastLlmMessage("Invalid LLM Response.");
}
else
{
document.SetDocumentState(llmResponse.Success ? EDocumentState.Success : EDocumentState.Failed);
document.SetLastLlmMessage(llmResponse.Message);
}
await repository.Update(document);
}
private async Task UnloadModel()
{
await using var scope = scopeFactory.CreateAsyncScope();
var agentService = scope.ServiceProvider.GetRequiredService<LLMAgentService>();
logger.LogInformation($"Unloading Model");
isWorking = true;
await agentService.UnloadModel();
isWorking = false;
}
private async Task<LmStudioLlmResponse> ProcessDocument(PaperlessDocument docToProcess)
{
await using var scope = scopeFactory.CreateAsyncScope();
var agentService = scope.ServiceProvider.GetRequiredService<LLMAgentService>();
var repository = scope.ServiceProvider.GetRequiredService<PaperlessDocumentRepository>();
isWorking = true;
logger.LogInformation($"Processing: {docToProcess}");
docToProcess.DocumentState = EDocumentState.Started;
await repository.Update(docToProcess);
var llmResponse = await agentService.ProcessDocumentWithAI(docToProcess);
isWorking = false;
return llmResponse ?? new LmStudioLlmResponse();
}
}
class PaperlessDocumentSameDocument : EqualityComparer<PaperlessDocument>
{
public override bool Equals(PaperlessDocument? x, PaperlessDocument? y)
{
if (x == null && y == null)
return true;
else if (x == null || y == null)
return false;
return x.Id == y.Id || x.DocumentId == y.DocumentId;
}
public override int GetHashCode([DisallowNull] PaperlessDocument obj)
{
var hcode = obj.Id + obj.DocumentId;
return hcode.GetHashCode();
}
}