코워크 PPT 생성 경로를 공통 품질 루프로 고도화하고 자동 보정 단계를 추가
- Cowork 프롬프트와 direct-creation 탐색 정책에서 PPT 요청은 document_plan을 무조건 선행하지 않고 pptx_create를 우선하도록 조정했습니다. - DeckPlanningService에 RefineForQuality 루프를 추가해 executive summary, comparison, roadmap, chart, KPI dashboard 슬라이드의 headline, takeaway, verdict, timeline/owner, KPI narrative를 자동 보강하도록 했습니다. - PptxSkill이 초기 deck review가 약할 때 한 번 더 refined deck을 만들고 실제로 점수와 경고가 개선된 경우에만 최종 렌더링에 반영하도록 수정했습니다. - DeckPlanningServiceTests와 PptxSkillAutoRepairTests를 확장해 generic PPT 품질 보정 회귀를 고정했습니다. - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_ppt_generic_quality\\ -p:IntermediateOutputPath=obj\\verify_ppt_generic_quality\\ (경고 0 / 오류 0) - 검증: deck planning, pptx auto repair, golden deck, deck quality review 테스트 통과 14
This commit is contained in:
@@ -98,4 +98,97 @@ public class DeckPlanningServiceTests
|
||||
layouts.Should().Contain("comparison");
|
||||
layouts.Should().Contain("roadmap");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefineForQuality_ShouldStrengthenWeakSpecializedSlides()
|
||||
{
|
||||
using var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"title": "Executive Operating Review",
|
||||
"objective": "improve execution quality",
|
||||
"decision_ask": "approve the first delivery wave",
|
||||
"slides": [
|
||||
{
|
||||
"layout": "executive_summary",
|
||||
"title": "Executive Summary",
|
||||
"body": [
|
||||
"Improve execution quality",
|
||||
"Approve the first delivery wave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "comparison",
|
||||
"title": "Execution Options",
|
||||
"options": [
|
||||
{ "name": "Pilot" },
|
||||
{ "name": "Wave rollout" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "roadmap",
|
||||
"title": "Roadmap",
|
||||
"phases": [
|
||||
{ "title": "Kickoff", "owner": "담당 미정" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "chart",
|
||||
"title": "Trend",
|
||||
"chart_labels": ["Q1", "Q2", "Q3"],
|
||||
"chart_values": [100, 120, 138]
|
||||
},
|
||||
{
|
||||
"layout": "kpi_dashboard",
|
||||
"title": "KPI Snapshot",
|
||||
"kpis": [
|
||||
{ "label": "Revenue", "value": "+12%" },
|
||||
{ "label": "Cycle Time", "value": "-8%" },
|
||||
{ "label": "Quality", "value": "97%" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
""");
|
||||
|
||||
using var prepared = DeckPlanningService.Prepare(args.RootElement, args.RootElement.GetProperty("slides"), "Executive Operating Review");
|
||||
var review = DeckQualityReviewService.ReviewDeck(
|
||||
"Executive Operating Review",
|
||||
prepared.Slides,
|
||||
hasTemplate: false,
|
||||
prepared.AutoRepairCount,
|
||||
prepared.Storyline);
|
||||
|
||||
using var refined = DeckPlanningService.RefineForQuality(prepared, review, "Executive Operating Review");
|
||||
var slides = refined.Slides.EnumerateArray().ToList();
|
||||
|
||||
var executive = slides.First(slide => slide.GetProperty("layout").GetString() == "executive_summary");
|
||||
executive.TryGetProperty("summary_points", out var executivePoints).Should().BeTrue();
|
||||
executivePoints.GetArrayLength().Should().BeGreaterThan(0);
|
||||
executive.TryGetProperty("kpis", out var executiveKpis).Should().BeTrue();
|
||||
executiveKpis.GetArrayLength().Should().BeGreaterThan(0);
|
||||
|
||||
var comparison = slides.First(slide => slide.GetProperty("layout").GetString() == "comparison");
|
||||
comparison.TryGetProperty("options", out var options).Should().BeTrue();
|
||||
options[0].GetProperty("verdict").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
options[0].GetProperty("summary").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
|
||||
var roadmap = slides.First(slide => slide.GetProperty("layout").GetString() == "roadmap");
|
||||
var firstPhase = roadmap.GetProperty("phases")[0];
|
||||
firstPhase.GetProperty("owner").GetString().Should().NotContain("미정");
|
||||
firstPhase.GetProperty("timeline").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
firstPhase.GetProperty("detail").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
|
||||
var chart = slides.First(slide => slide.GetProperty("layout").GetString() == "chart");
|
||||
chart.TryGetProperty("summary_points", out var chartPoints).Should().BeTrue();
|
||||
chartPoints.GetArrayLength().Should().BeGreaterThan(0);
|
||||
|
||||
var kpi = slides.First(slide => slide.GetProperty("layout").GetString() == "kpi_dashboard");
|
||||
kpi.TryGetProperty("summary_points", out var kpiPoints).Should().BeTrue();
|
||||
kpiPoints.GetArrayLength().Should().BeGreaterThan(0);
|
||||
kpi.GetProperty("kpis")[0].GetProperty("trend").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
kpi.GetProperty("kpis")[0].GetProperty("note").GetString().Should().NotBeNullOrWhiteSpace();
|
||||
|
||||
refined.AutoRepairCount.Should().BeGreaterThan(prepared.AutoRepairCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,5 +75,91 @@ public class PptxSkillAutoRepairTests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ShouldRefineWeakDeckBeforeExport()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-pptx-refine-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var tool = new PptxSkill();
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "refined-deck.pptx",
|
||||
"title": "Quarterly Steering Deck",
|
||||
"objective": "approve the next delivery wave",
|
||||
"slides": [
|
||||
{
|
||||
"layout": "executive_summary",
|
||||
"title": "Executive Summary",
|
||||
"body": [
|
||||
"Approve the next delivery wave",
|
||||
"The delivery plan should move forward"
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "comparison",
|
||||
"title": "Options",
|
||||
"options": [
|
||||
{ "name": "Conservative" },
|
||||
{ "name": "Balanced" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "roadmap",
|
||||
"title": "Roadmap",
|
||||
"phases": [
|
||||
{ "title": "Kickoff", "owner": "담당 미정" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "chart",
|
||||
"title": "Trend",
|
||||
"chart_labels": ["Jan", "Feb", "Mar"],
|
||||
"chart_values": [10, 13, 16]
|
||||
},
|
||||
{
|
||||
"layout": "kpi_dashboard",
|
||||
"title": "KPI Snapshot",
|
||||
"kpis": [
|
||||
{ "label": "Revenue", "value": "+9%" },
|
||||
{ "label": "Cycle Time", "value": "-6%" },
|
||||
{ "label": "Stability", "value": "96%" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("PPT quality");
|
||||
result.Output.Should().Contain("Needs work: none");
|
||||
result.Output.Should().Contain("Auto-repair:");
|
||||
File.Exists(Path.Combine(workDir, "refined-deck.pptx")).Should().BeTrue();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user