문서 품질 critic와 golden 회귀를 고도화해 PPTX·HTML·DOCX·XLSX 마감 품질을 강화한다
- ArtifactQualityReviewService를 확장해 HTML의 board/strategy decision gap, DOCX evidence table·callout 부족, XLSX dashboard trend·variance·sheet summary·headline tile 부족을 개별 이슈로 판정하도록 보강 - ArtifactRepairGuideService와 DeckRepairGuideService를 보강해 decision summary, next steps, evidence table, trend/variance, dashboard tile 등 실제 보강 행동을 바로 제안하는 repair guide를 반환하도록 정리 - ExcelSkill review 입력을 세분화하고 Html/PPT golden 테스트를 strategy brief, PMO steering 시나리오까지 확대해 문서군 golden 회귀 범위를 넓힘 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_finish_batch\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal (ArtifactQualityReviewServiceTests, ArtifactRepairGuideServiceTests, DeckQualityReviewServiceTests, DeckRepairGuideServiceTests, HtmlSkillGoldenReportTests, PptxSkillGoldenDeckTests, DocxSkillGoldenDocumentTests, ExcelSkillGoldenWorkbookTests) -p:OutputPath=bin\\verify_doc_finish_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch_tests\
This commit is contained in:
@@ -73,7 +73,10 @@ public sealed record WorkbookReviewInput(
|
||||
bool HasActionSection,
|
||||
bool HasScorecardSection,
|
||||
bool HasDecisionSection,
|
||||
bool HasSheetSummarySection);
|
||||
bool HasSheetSummarySection,
|
||||
bool HasTrendSection,
|
||||
bool HasVarianceSection,
|
||||
bool HasDashboardTileSection);
|
||||
|
||||
public static class ArtifactQualityReviewService
|
||||
{
|
||||
@@ -131,13 +134,33 @@ public static class ArtifactQualityReviewService
|
||||
var boardPanelCount = Regex.Matches(html, @"board-report-panel", RegexOptions.IgnoreCase).Count;
|
||||
var strategyBriefCount = Regex.Matches(html, @"strategy-brief-panel", RegexOptions.IgnoreCase).Count;
|
||||
var kpiCount = Regex.Matches(html, @"kpi-card|kpi-grid|metric-card", RegexOptions.IgnoreCase).Count;
|
||||
var majorSectionEstimate = sectionCount
|
||||
+ (boardPanelCount > 0 ? 1 : 0)
|
||||
+ (strategyBriefCount > 0 ? 1 : 0)
|
||||
+ (comparisonCount > 0 ? 1 : 0)
|
||||
+ (roadmapCount > 0 ? 1 : 0)
|
||||
+ (matrixCount > 0 ? 1 : 0)
|
||||
+ (decisionCount > 0 ? 1 : 0)
|
||||
+ (evidenceCardCount > 0 ? 1 : 0)
|
||||
+ (kpiCount > 0 ? 1 : 0);
|
||||
var supportingBlockEstimate = paragraphCount
|
||||
+ tableCount
|
||||
+ calloutCount
|
||||
+ comparisonCount
|
||||
+ roadmapCount
|
||||
+ matrixCount
|
||||
+ decisionCount
|
||||
+ evidenceCardCount
|
||||
+ boardPanelCount
|
||||
+ strategyBriefCount
|
||||
+ (kpiCount > 0 ? 1 : 0);
|
||||
var placeholderCount = CountPlaceholders(html);
|
||||
|
||||
if (hasCover) strengths.Add("Includes cover page");
|
||||
if (hasTableOfContents) strengths.Add("Includes table of contents");
|
||||
if (printReady) strengths.Add("Includes print-ready CSS");
|
||||
if (hasPrintFrame) strengths.Add("Includes print header/footer frame");
|
||||
if (sectionCount >= 5) strengths.Add($"Contains {sectionCount} major sections");
|
||||
if (majorSectionEstimate >= 5) strengths.Add($"Contains {majorSectionEstimate} major sections");
|
||||
if (tableCount > 0 || comparisonCount > 0 || roadmapCount > 0 || matrixCount > 0 || decisionCount > 0 || evidenceCardCount > 0 || boardPanelCount > 0 || strategyBriefCount > 0 || kpiCount > 0)
|
||||
strengths.Add("Uses structured business blocks");
|
||||
if (calloutCount > 0) strengths.Add("Uses callout blocks for emphasis");
|
||||
@@ -146,9 +169,9 @@ public static class ArtifactQualityReviewService
|
||||
|
||||
if (html.Length < 1800)
|
||||
issues.Add(new("Body content may be too short for an executive-quality document.", ArtifactReviewSeverity.Warning));
|
||||
if (sectionCount < 4)
|
||||
if (majorSectionEstimate < 4)
|
||||
issues.Add(new("Major section count is low for a business report.", ArtifactReviewSeverity.Warning));
|
||||
if (paragraphCount < sectionCount * 2)
|
||||
if (supportingBlockEstimate < Math.Max(4, majorSectionEstimate * 2))
|
||||
issues.Add(new("Several sections may need more supporting paragraphs.", ArtifactReviewSeverity.Warning));
|
||||
if (tableCount + comparisonCount + roadmapCount + matrixCount + decisionCount + evidenceCardCount + boardPanelCount + strategyBriefCount + kpiCount == 0)
|
||||
issues.Add(new("Structured visual blocks are limited.", ArtifactReviewSeverity.Warning));
|
||||
@@ -158,12 +181,16 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Executive summary or summary section is missing.", ArtifactReviewSeverity.Warning));
|
||||
if (printReady && !hasPrintFrame)
|
||||
issues.Add(new("Print-ready export is missing a print header/footer frame.", ArtifactReviewSeverity.Info));
|
||||
if (printReady && sectionCount >= 4 && decisionCount + evidenceCardCount == 0)
|
||||
if (printReady && majorSectionEstimate >= 4 && decisionCount + evidenceCardCount == 0)
|
||||
issues.Add(new("Print-ready business report would benefit from decision summary or evidence cards.", ArtifactReviewSeverity.Warning));
|
||||
if (printReady && !hasCover && sectionCount >= 5)
|
||||
if (printReady && !hasCover && majorSectionEstimate >= 5)
|
||||
issues.Add(new("Print-ready report could benefit from a cover page.", ArtifactReviewSeverity.Info));
|
||||
if (boardPanelCount > 0 && decisionCount == 0)
|
||||
issues.Add(new("Board-ready report should include a decision summary block.", ArtifactReviewSeverity.Warning));
|
||||
if (boardPanelCount > 0 && evidenceCardCount == 0 && tableCount == 0)
|
||||
issues.Add(new("Board-ready report would benefit from evidence cards or a supporting table.", ArtifactReviewSeverity.Info));
|
||||
if (strategyBriefCount > 0 && decisionCount == 0)
|
||||
issues.Add(new("Strategy brief should include explicit decisions or a decision summary block.", ArtifactReviewSeverity.Warning));
|
||||
if (strategyBriefCount > 0 && comparisonCount + roadmapCount == 0)
|
||||
issues.Add(new("Strategy brief would be stronger with a comparison or roadmap block.", ArtifactReviewSeverity.Info));
|
||||
|
||||
@@ -202,6 +229,10 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Recommendation or next-step section is missing.", ArtifactReviewSeverity.Warning));
|
||||
if (input.SectionCount >= 6 && !input.HasAppendixSection)
|
||||
issues.Add(new("Appendix or reference section is limited for a long document.", ArtifactReviewSeverity.Info));
|
||||
if (input.SectionCount >= 5 && input.TableCount == 0)
|
||||
issues.Add(new("Supporting evidence table is limited for a business document.", ArtifactReviewSeverity.Info));
|
||||
if (input.SectionCount >= 5 && input.CalloutCount + input.HighlightCount == 0)
|
||||
issues.Add(new("Key messages would benefit from callout or highlight blocks.", ArtifactReviewSeverity.Info));
|
||||
if (input.TableCount + input.ListCount + input.CalloutCount + input.HighlightCount == 0)
|
||||
issues.Add(new("Document structure is mostly plain paragraphs.", ArtifactReviewSeverity.Warning));
|
||||
|
||||
@@ -248,6 +279,14 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Dashboard sheet should link to supporting detail sheets.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && input.FormulaCount < 3)
|
||||
issues.Add(new("Dashboard sheet would benefit from more calculated trend or variance formulas.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && !input.HasTrendSection && !input.HasVarianceSection)
|
||||
issues.Add(new("Dashboard sheet lacks trend or variance framing for the supporting sheets.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && !input.HasSheetSummarySection)
|
||||
issues.Add(new("Dashboard workbook should summarize each supporting detail sheet.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDecisionSection && !input.HasActionSection)
|
||||
issues.Add(new("Decision summary is present but follow-up actions are limited.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && !input.HasDashboardTileSection && !input.HasHighlightSection)
|
||||
issues.Add(new("Dashboard sheet would benefit from headline tiles or highlight callouts.", ArtifactReviewSeverity.Info));
|
||||
|
||||
return BuildReport("xlsx", strengths, issues);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,12 @@ public static class ArtifactRepairGuideService
|
||||
|
||||
private static string? BuildHtmlAction(string message)
|
||||
{
|
||||
if (message.Contains("Board-ready report should include a decision summary block", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a decision summary block directly after the board ask so the approval point is explicit";
|
||||
if (message.Contains("decision summary or evidence cards", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a decision summary and evidence cards near the recommendation section";
|
||||
if (message.Contains("Strategy brief should include explicit decisions", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add an explicit decisions block or decision summary to the strategy brief";
|
||||
if (message.Contains("cover page", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a cover page for print-ready or board-facing reports";
|
||||
if (message.Contains("table of contents", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -57,14 +61,22 @@ public static class ArtifactRepairGuideService
|
||||
return "Add KPI, trend, or decision blocks so the dashboard communicates the core story at a glance";
|
||||
if (message.Contains("dashboard sheet", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a dashboard sheet with KPI tiles, trends, and links to detail sheets";
|
||||
if (message.Contains("trend or variance framing", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add trend and variance blocks so the dashboard explains what changed across the detail sheets";
|
||||
if (message.Contains("summarize each supporting detail sheet", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add sheet summaries so each detail tab rolls up into the dashboard story";
|
||||
if (message.Contains("Summary sheet could better surface", StringComparison.OrdinalIgnoreCase))
|
||||
return "Promote KPIs, decisions, and highlights into the summary or dashboard sheet";
|
||||
if (message.Contains("Dashboard sheet could better call out highlights or actions", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add highlight and action callout blocks to the dashboard sheet";
|
||||
if (message.Contains("headline tiles or highlight callouts", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add dashboard tiles or highlight callouts to surface the top-line business message";
|
||||
if (message.Contains("Dashboard sheet should link", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add hyperlinks from the dashboard to each supporting detail sheet";
|
||||
if (message.Contains("trend or variance formulas", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add trend, variance, or rollup formulas so the dashboard summarizes detail sheets";
|
||||
if (message.Contains("follow-up actions are limited", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add explicit follow-up actions so each dashboard decision has a named next step";
|
||||
if (message.Contains("data validation", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add data validation rules for editable status, owner, or category columns";
|
||||
if (message.Contains("Conditional formatting", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -92,6 +104,10 @@ public static class ArtifactRepairGuideService
|
||||
return "Add a recommendation or next-step section with a clear decision ask";
|
||||
if (message.Contains("Appendix", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add an appendix or reference section for longer documents";
|
||||
if (message.Contains("evidence table", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add at least one supporting evidence table so key claims are traceable";
|
||||
if (message.Contains("callout or highlight blocks", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add callout or highlight blocks to surface the most important messages";
|
||||
if (message.Contains("mostly plain paragraphs", StringComparison.OrdinalIgnoreCase))
|
||||
return "Introduce tables, lists, or callout blocks to break up dense prose";
|
||||
if (message.Contains("too short", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -207,6 +207,11 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: Executive Summary needs more supporting points.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(ReadString(slide, "recommendation")))
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: Executive Summary should include a recommendation or decision ask.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "recommendation":
|
||||
if (string.IsNullOrWhiteSpace(ReadString(slide, "recommendation")))
|
||||
@@ -214,6 +219,12 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: recommendation text is missing.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
if (ReadStringList(slide, "summary_points").Count == 0 &&
|
||||
ReadStringList(slide, "next_steps").Count == 0)
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: recommendation slide needs supporting rationale or next steps.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "comparison":
|
||||
if (ReadJsonArrayCount(slide, "options") < 2)
|
||||
@@ -228,6 +239,11 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: roadmap slide is missing phases.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
else if (ReadJsonArrayCount(slide, "phases") < 2)
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: roadmap slide should show at least two phases.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "chart":
|
||||
if (ReadJsonArrayCount(slide, "chart_labels") == 0 || ReadJsonArrayCount(slide, "chart_values") == 0)
|
||||
|
||||
@@ -12,8 +12,12 @@ public static class DeckRepairGuideService
|
||||
{
|
||||
var action = issue.Message switch
|
||||
{
|
||||
var message when message.Contains("decision ask", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add a recommendation or decision ask directly to the Executive Summary",
|
||||
var message when message.Contains("Executive Summary", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add or strengthen the Executive Summary with 2-3 evidence-backed takeaways",
|
||||
var message when message.Contains("supporting rationale or next steps", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add supporting rationale or next steps so the recommendation turns into action",
|
||||
var message when message.Contains("Recommendation", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add a clear recommendation or decision request slide near the end of the deck",
|
||||
var message when message.Contains("roadmap", StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
@@ -221,6 +221,9 @@ public class ExcelSkill : IAgentTool
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
foreach (var line in ArtifactQualityOutputFormatter.BuildLines(review))
|
||||
features += $"\n{line}";
|
||||
@@ -332,7 +335,10 @@ public class ExcelSkill : IAgentTool
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis") || HasSummaryItems(summarySheet, "trend_series") || HasSummaryItems(summarySheet, "dashboard_tiles") || HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
HasSummaryItems(summarySheet, "sheet_summaries"),
|
||||
HasSummaryItems(summarySheet, "trend_series"),
|
||||
HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasSummaryItems(summarySheet, "dashboard_tiles")));
|
||||
foreach (var line in ArtifactQualityOutputFormatter.BuildLines(review))
|
||||
features += $"\n{line}";
|
||||
|
||||
@@ -477,7 +483,10 @@ public class ExcelSkill : IAgentTool
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis") || HasSummaryItems(summarySheet, "trend_series") || HasSummaryItems(summarySheet, "dashboard_tiles") || HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
HasSummaryItems(summarySheet, "sheet_summaries"),
|
||||
HasSummaryItems(summarySheet, "trend_series"),
|
||||
HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasSummaryItems(summarySheet, "dashboard_tiles")));
|
||||
var outputLines = new List<string>
|
||||
{
|
||||
$"Excel 파일 생성 완료: {fullPath}",
|
||||
|
||||
Reference in New Issue
Block a user