문서 고도화 다음 단계를 반영해 엑셀 summary와 DOCX 조립 품질을 끌어올렸습니다
핵심 수정사항: - ExcelSkill summary_sheet에 decision_summary, scorecards, sheet_summaries를 추가해 dashboard형 summary 시트를 생성하도록 확장했습니다. - ArtifactQualityReviewService의 workbook 리뷰 입력을 확장해 KPI/decision/detail summary 존재 여부를 품질 점수와 보완 포인트에 반영했습니다. - DocumentAssemblerTool에 style_map 파라미터를 추가해 template 기반 DOCX 조립에서 title/heading/body 문단 스타일을 실제 Word 스타일로 매핑하도록 개선했습니다. - DocumentAssemblerStyleMapTests, ExcelSkillDashboardSummaryTests를 추가하고 기존 ArtifactQualityReviewServiceTests를 갱신했습니다. 검증 결과: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_next2\\ -p:IntermediateOutputPath=obj\\verify_doc_next2\\ : 경고 0 / 오류 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|DocumentAssemblerStyleMapTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|ExcelSkillDashboardSummaryTests|ExcelSkillSummarySheetTests|ExcelSkillExecutiveSummaryLinkTests|ExcelSkillDataValidationTests|ExcelSkillConditionalFormattingTests" -p:OutputPath=bin\\verify_doc_next2_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_next2_tests\\ : 통과 11
This commit is contained in:
@@ -217,7 +217,10 @@ public class ExcelSkill : IAgentTool
|
||||
conditionalFormattingCount,
|
||||
false,
|
||||
false,
|
||||
summaryArg.ValueKind == JsonValueKind.Object));
|
||||
summaryArg.ValueKind == JsonValueKind.Object,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
features += $"\n{review.ToToolSummary()}";
|
||||
|
||||
return ToolResult.Ok(
|
||||
@@ -305,7 +308,10 @@ public class ExcelSkill : IAgentTool
|
||||
conditionalFormattingCount,
|
||||
true,
|
||||
HasSummaryItems(summarySheet, "highlights"),
|
||||
HasSummaryItems(summarySheet, "actions")));
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
features += $"\n{review.ToToolSummary()}";
|
||||
|
||||
return ToolResult.Ok(
|
||||
@@ -428,7 +434,10 @@ public class ExcelSkill : IAgentTool
|
||||
totalConditionalFormattingCount,
|
||||
summarySheet.ValueKind == JsonValueKind.Object,
|
||||
HasSummaryItems(summarySheet, "highlights"),
|
||||
HasSummaryItems(summarySheet, "actions")));
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
return ToolResult.Ok(
|
||||
$"Excel 파일 생성 완료: {fullPath}\n시트: {totalSheets}개, 총 데이터 행: {totalRows}\n{review.ToToolSummary()}",
|
||||
fullPath);
|
||||
@@ -471,6 +480,9 @@ public class ExcelSkill : IAgentTool
|
||||
|
||||
rowIndex++;
|
||||
|
||||
AppendDecisionSummarySection(summarySheet, sheetData, merges, ref rowIndex);
|
||||
AppendScorecardSection(summarySheet, sheetData, ref rowIndex);
|
||||
|
||||
if (summarySheet.SafeTryGetProperty("kpis", out var kpis) && kpis.ValueKind == JsonValueKind.Array && kpis.GetArrayLength() > 0)
|
||||
{
|
||||
AppendMergedTextRow(sheetData, merges, rowIndex++, "A", "F", "Key KPIs", 1);
|
||||
@@ -497,6 +509,7 @@ public class ExcelSkill : IAgentTool
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
AppendSheetSummarySection(summarySheet, sheetData, ref rowIndex);
|
||||
AppendSummaryTextSection(summarySheet, "highlights", "Key Highlights", sheetData, merges, ref rowIndex);
|
||||
AppendSummaryTextSection(summarySheet, "actions", "Next Actions", sheetData, merges, ref rowIndex);
|
||||
|
||||
@@ -530,6 +543,115 @@ public class ExcelSkill : IAgentTool
|
||||
}
|
||||
}
|
||||
|
||||
private static void AppendDecisionSummarySection(JsonElement summarySheet, SheetData sheetData, MergeCells merges, ref uint rowIndex)
|
||||
{
|
||||
if (!summarySheet.SafeTryGetProperty("decision_summary", out var decisionSummary))
|
||||
return;
|
||||
|
||||
var appended = false;
|
||||
if (decisionSummary.ValueKind == JsonValueKind.Array && decisionSummary.GetArrayLength() > 0)
|
||||
{
|
||||
AppendMergedTextRow(sheetData, merges, rowIndex++, "A", "F", "Decision Summary", 1);
|
||||
foreach (var item in decisionSummary.EnumerateArray())
|
||||
{
|
||||
var label = item.SafeTryGetProperty("label", out var labelEl) ? labelEl.SafeGetString() ?? "" : "";
|
||||
var value = item.SafeTryGetProperty("value", out var valueEl) ? valueEl.SafeGetString() ?? "" : "";
|
||||
var owner = item.SafeTryGetProperty("owner", out var ownerEl) ? ownerEl.SafeGetString() ?? "" : "";
|
||||
|
||||
var row = new Row { RowIndex = rowIndex++ };
|
||||
row.Append(CreateSummaryCell("A", row.RowIndex!.Value, label, 1));
|
||||
row.Append(CreateSummaryCell("B", row.RowIndex!.Value, value, 3));
|
||||
row.Append(CreateSummaryCell("C", row.RowIndex!.Value, owner, 0));
|
||||
sheetData.Append(row);
|
||||
appended = true;
|
||||
}
|
||||
}
|
||||
else if (decisionSummary.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
AppendMergedTextRow(sheetData, merges, rowIndex++, "A", "F", "Decision Summary", 1);
|
||||
foreach (var property in decisionSummary.EnumerateObject())
|
||||
{
|
||||
var row = new Row { RowIndex = rowIndex++ };
|
||||
row.Append(CreateSummaryCell("A", row.RowIndex!.Value, property.Name, 1));
|
||||
row.Append(CreateSummaryCell("B", row.RowIndex!.Value, property.Value.SafeGetString() ?? property.Value.ToString(), 3));
|
||||
sheetData.Append(row);
|
||||
appended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (appended)
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
private static void AppendScorecardSection(JsonElement summarySheet, SheetData sheetData, ref uint rowIndex)
|
||||
{
|
||||
JsonElement scorecards;
|
||||
var hasScorecards = summarySheet.SafeTryGetProperty("scorecards", out scorecards)
|
||||
&& scorecards.ValueKind == JsonValueKind.Array
|
||||
&& scorecards.GetArrayLength() > 0;
|
||||
if (!hasScorecards)
|
||||
{
|
||||
hasScorecards = summarySheet.SafeTryGetProperty("cards", out scorecards)
|
||||
&& scorecards.ValueKind == JsonValueKind.Array
|
||||
&& scorecards.GetArrayLength() > 0;
|
||||
}
|
||||
|
||||
if (!hasScorecards)
|
||||
return;
|
||||
|
||||
var headerRow = new Row { RowIndex = rowIndex++ };
|
||||
headerRow.Append(CreateSummaryCell("A", headerRow.RowIndex!.Value, "Scorecards", 1));
|
||||
headerRow.Append(CreateSummaryCell("B", headerRow.RowIndex!.Value, "Value", 1));
|
||||
headerRow.Append(CreateSummaryCell("C", headerRow.RowIndex!.Value, "Status", 1));
|
||||
headerRow.Append(CreateSummaryCell("D", headerRow.RowIndex!.Value, "Note", 1));
|
||||
sheetData.Append(headerRow);
|
||||
|
||||
var cardIndex = 0;
|
||||
foreach (var card in scorecards.EnumerateArray())
|
||||
{
|
||||
var row = new Row { RowIndex = rowIndex++ };
|
||||
var stripeStyle = cardIndex % 2 == 0 ? (uint)0 : (uint)2;
|
||||
row.Append(CreateSummaryCell("A", row.RowIndex!.Value, card.SafeTryGetProperty("label", out var labelEl) ? labelEl.SafeGetString() ?? "" : "", 1));
|
||||
row.Append(CreateSummaryCell("B", row.RowIndex!.Value, card.SafeTryGetProperty("value", out var valueEl) ? valueEl.SafeGetString() ?? "" : "", 3));
|
||||
row.Append(CreateSummaryCell("C", row.RowIndex!.Value, card.SafeTryGetProperty("status", out var statusEl) ? statusEl.SafeGetString() ?? "" : "", stripeStyle));
|
||||
row.Append(CreateSummaryCell("D", row.RowIndex!.Value, card.SafeTryGetProperty("note", out var noteEl) ? noteEl.SafeGetString() ?? "" : "", stripeStyle));
|
||||
sheetData.Append(row);
|
||||
cardIndex++;
|
||||
}
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
private static void AppendSheetSummarySection(JsonElement summarySheet, SheetData sheetData, ref uint rowIndex)
|
||||
{
|
||||
if (!summarySheet.SafeTryGetProperty("sheet_summaries", out var sheetSummaries)
|
||||
|| sheetSummaries.ValueKind != JsonValueKind.Array
|
||||
|| sheetSummaries.GetArrayLength() == 0)
|
||||
return;
|
||||
|
||||
var headerRow = new Row { RowIndex = rowIndex++ };
|
||||
headerRow.Append(CreateSummaryCell("A", headerRow.RowIndex!.Value, "Sheet", 1));
|
||||
headerRow.Append(CreateSummaryCell("B", headerRow.RowIndex!.Value, "Status", 1));
|
||||
headerRow.Append(CreateSummaryCell("C", headerRow.RowIndex!.Value, "Summary", 1));
|
||||
headerRow.Append(CreateSummaryCell("D", headerRow.RowIndex!.Value, "Owner", 1));
|
||||
sheetData.Append(headerRow);
|
||||
|
||||
var summaryIndex = 0;
|
||||
foreach (var sheetSummary in sheetSummaries.EnumerateArray())
|
||||
{
|
||||
var row = new Row { RowIndex = rowIndex++ };
|
||||
var stripeStyle = summaryIndex % 2 == 0 ? (uint)0 : (uint)2;
|
||||
row.Append(CreateSummaryCell("A", row.RowIndex!.Value, sheetSummary.SafeTryGetProperty("sheet", out var sheetEl) ? sheetEl.SafeGetString() ?? "" : "", 1));
|
||||
row.Append(CreateSummaryCell("B", row.RowIndex!.Value, sheetSummary.SafeTryGetProperty("status", out var statusEl) ? statusEl.SafeGetString() ?? "" : "", 3));
|
||||
row.Append(CreateSummaryCell("C", row.RowIndex!.Value, sheetSummary.SafeTryGetProperty("summary", out var summaryEl) ? summaryEl.SafeGetString() ?? "" : "", stripeStyle));
|
||||
row.Append(CreateSummaryCell("D", row.RowIndex!.Value, sheetSummary.SafeTryGetProperty("owner", out var ownerEl) ? ownerEl.SafeGetString() ?? "" : "", stripeStyle));
|
||||
sheetData.Append(row);
|
||||
summaryIndex++;
|
||||
}
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
private static void AppendSummaryTextSection(JsonElement summarySheet, string key, string heading, SheetData sheetData, MergeCells merges, ref uint rowIndex)
|
||||
{
|
||||
if (!summarySheet.SafeTryGetProperty(key, out var items) || items.ValueKind != JsonValueKind.Array || items.GetArrayLength() == 0)
|
||||
@@ -1235,6 +1357,20 @@ public class ExcelSkill : IAgentTool
|
||||
&& items.GetArrayLength() > 0;
|
||||
}
|
||||
|
||||
private static bool HasStructuredSummaryContent(JsonElement summarySheet, string propertyName)
|
||||
{
|
||||
if (summarySheet.ValueKind != JsonValueKind.Object
|
||||
|| !summarySheet.SafeTryGetProperty(propertyName, out var value))
|
||||
return false;
|
||||
|
||||
return value.ValueKind switch
|
||||
{
|
||||
JsonValueKind.Array => value.GetArrayLength() > 0,
|
||||
JsonValueKind.Object => value.EnumerateObject().Any(),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildFeatureList(bool isStyled, bool freezeHeader,
|
||||
bool hasMerges, bool hasSummary, bool hasNumFmts, bool hasAlignments, string? theme)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user