From de9a0c29783e032e826fc84e3ffce7029a5f5d6e Mon Sep 17 00:00:00 2001 From: glz <694770232@qq.com> Date: Wed, 8 Jul 2026 17:07:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor(work-service,print-worker):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E4=B8=8E?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 提取评分prompt构建逻辑减少重复代码 2. 移除冗余的参考答案图片循环逻辑 3. 重构打印服务的错误回调逻辑,统一失败处理流程 4. 新增打印服务的任务取消处理逻辑 --- .../Consumers/AutoDotCodeConsumer.cs | 47 +++++++++++++++---- .../Consumers/JournalTaskReceiveConsumer.cs | 33 ++----------- ...YZH.InteractiveMagazine.WorkService.csproj | 2 +- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/QYZH.InteractiveMagazine.PrintWorker/Consumers/AutoDotCodeConsumer.cs b/QYZH.InteractiveMagazine.PrintWorker/Consumers/AutoDotCodeConsumer.cs index cead891..e785f5d 100644 --- a/QYZH.InteractiveMagazine.PrintWorker/Consumers/AutoDotCodeConsumer.cs +++ b/QYZH.InteractiveMagazine.PrintWorker/Consumers/AutoDotCodeConsumer.cs @@ -47,10 +47,11 @@ public class AutoDotCodeConsumer( using var scope = scopeFactory.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); + JournalPagePrintDto? request = null; try { - var request = JsonSerializer.Deserialize(message, new JsonSerializerOptions + request = JsonSerializer.Deserialize(message, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); @@ -72,6 +73,7 @@ public class AutoDotCodeConsumer( if (string.IsNullOrWhiteSpace(journalPdfKey)) { logger.LogError("书籍上传 PDF 文件地址为空,JournalId: {JournalId}", request.JournalId); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -79,6 +81,7 @@ public class AutoDotCodeConsumer( if (pdfStream == null) { logger.LogError("获取书籍上传 PDF 文件失败,OSS Key: {OssKey}", journalPdfKey); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -93,6 +96,7 @@ public class AutoDotCodeConsumer( if (dotFile == null) { logger.LogError("配置打印数据错误,点阵文件不存在,DotId: {DotId}", dotId); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -101,7 +105,7 @@ public class AutoDotCodeConsumer( if (!File.Exists(exePath)) { logger.LogError("PrintTool.exe 不存在,路径:{ExePath}", exePath); - await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -109,7 +113,7 @@ public class AutoDotCodeConsumer( if (!File.Exists(xmlPath)) { logger.LogError("铺码授权文件不存在,路径:{XmlPath}", xmlPath); - await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -126,7 +130,7 @@ public class AutoDotCodeConsumer( if (dotFileDetailList.Count < pageNumMax) { logger.LogError("点阵页码余量不足,DotId: {DotId}, Need: {Need}, Available: {Available}", dotId, pageNumMax, dotFileDetailList.Count); - await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken); + await TryCallbackCodeFailAsync(request, cancellationToken); return; } @@ -138,7 +142,7 @@ public class AutoDotCodeConsumer( if (printResult.Timeout || printResult.ExitCode != 0) { logger.LogError("执行 PrintTool.exe 失败,退出码:{ExitCode},错误信息:{ErrorMessage}", printResult.ExitCode, printResult.Error); - await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request, dotFileDetailPageName), cancellationToken); + await TryCallbackCodeFailAsync(request, cancellationToken, dotFileDetailPageName); return; } @@ -150,8 +154,7 @@ public class AutoDotCodeConsumer( if (!ValidatePrintOutput(printResult.Output, dotFileDetailPageName, dPrint)) { - statusModel.Status = JournalStatusEnum.CodeFail; - await ExecuteUpdateJournalStatusAsync(statusModel, cancellationToken); + await TryCallbackCodeFailAsync(request, cancellationToken, dotFileDetailPageName); return; } @@ -192,10 +195,18 @@ public class AutoDotCodeConsumer( logger.LogError("回调接口修改书籍状态失败,JournalId: {JournalId},接口返回消息:{Message}", statusModel.JournalId, callbackResponse.Message); } } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + logger.LogWarning("自动铺码处理已取消,JournalId: {JournalId}", request?.JournalId); + throw; + } catch (Exception ex) { logger.LogError(ex, "自动铺码处理失败"); - throw; + if (request != null) + { + await TryCallbackCodeFailAsync(request, CancellationToken.None); + } } } @@ -298,6 +309,26 @@ public class AutoDotCodeConsumer( return new CallbackUpdateJournalStatusResponse(); } + private async Task TryCallbackCodeFailAsync(JournalPagePrintDto request, CancellationToken cancellationToken, string[]? pageNo = null) + { + try + { + var callbackResponse = await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request, pageNo), cancellationToken); + if (!callbackResponse.IsSuccess) + { + logger.LogError("回调接口修改书籍为铺码失败状态失败,JournalId: {JournalId},接口返回消息:{Message}", request.JournalId, callbackResponse.Message); + } + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + throw; + } + catch (Exception callbackEx) + { + logger.LogError(callbackEx, "铺码失败后请求回调接口失败,JournalId: {JournalId}", request.JournalId); + } + } + private static JournalPagePrintDto BuildFailResponse(JournalPagePrintDto request, string[]? pageNo = null) { return new JournalPagePrintDto diff --git a/QYZH.InteractiveMagazine.WorkService/Consumers/JournalTaskReceiveConsumer.cs b/QYZH.InteractiveMagazine.WorkService/Consumers/JournalTaskReceiveConsumer.cs index e2da403..62cb17f 100644 --- a/QYZH.InteractiveMagazine.WorkService/Consumers/JournalTaskReceiveConsumer.cs +++ b/QYZH.InteractiveMagazine.WorkService/Consumers/JournalTaskReceiveConsumer.cs @@ -233,13 +233,14 @@ public class JournalTaskReceiveConsumer( { throw new InvalidOperationException("AI聊天服务配置不完整,请检查 AiChat 配置节点"); } - + var answerMapPrompt = BuildScorePrompt(scoreUnit, referenceAnswerMap); + logger.LogInformation(answerMapPrompt); var content = new List { new { type = "text", - text = BuildScorePrompt(scoreUnit, referenceAnswerMap) + text = answerMapPrompt } }; @@ -251,7 +252,7 @@ public class JournalTaskReceiveConsumer( content.Add(new { type = "text", - text = $"以下为任务 {context.Task.Id} 的学生作答图片,共 {answerImages.Count} 张。" + text = $"以下是学生作答图片,共 {answerImages.Count} 张。" }); foreach (var answerImage in answerImages) @@ -269,31 +270,6 @@ public class JournalTaskReceiveConsumer( throw new InvalidOperationException($"评分单元 {scoreUnit.GroupId} 缺少答案图片"); } - foreach (var context in scoreUnit.Questions) - { - referenceAnswerMap.TryGetValue(context.Task.Id, out var referenceAnswers); - var referenceAnswerImages = await BuildReferenceAnswerImageContentsAsync(context.Task.Id, referenceAnswers ?? [], cancellationToken); - if (referenceAnswerImages.Count == 0) - { - continue; - } - - content.Add(new - { - type = "text", - text = $"以下为任务 {context.Task.Id} 的参考答案图片,共 {referenceAnswerImages.Count} 张。参考答案不是必有,评分时以题目Prompt和学生答案为主。" - }); - - foreach (var referenceAnswerImage in referenceAnswerImages) - { - content.Add(new - { - type = "image_url", - image_url = new { url = referenceAnswerImage.DataUrl } - }); - } - } - var requestBody = new { model, @@ -403,6 +379,7 @@ public class JournalTaskReceiveConsumer( prompt.AppendLine(" \"Completion\": 100,"); prompt.AppendLine(" \"Result\": \"50字内的中文评语\""); prompt.AppendLine("}"); + return prompt.ToString(); } diff --git a/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj b/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj index d427715..d594020 100644 --- a/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj +++ b/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj @@ -1,4 +1,4 @@ - + net8.0