?? planner/assembler ??? 2? ??
?? ??: - Word/HTML/Excel ?? ?? ??? PPT ??? planner ?? ??? ? ??? ??? ?? ?? ??? ?????. - ??? ???? document_plan ???? ?? ??? ? ??? xlsx scaffold ??? ?????. ?? ????: - DocumentPlannerTool? format:xlsx ??? ???? summary_sheet + sheets ??? excel_create scaffold? ????? ??????. - DocumentPlannerTool? ?? ?? ??? workbook/tracker/dashboard/scorecard ???? ????? ??????. - DocumentAssemblerTool? DOCX ?? ??? cover_subtitle, TOC, header/footer ??? ???? ?? ???? DOCX ?? ?? ??? ??????. - DocumentAssemblerTool? HTML ?? ??? ArtifactQualityReviewService? ??? score ?? ?? ??? ????? ??????. - kpi-workbook ???? document_plan ??? ??? complex workbook ?? ? planner ??? ??? ? ?? ????. - ?? ?? ???? DocumentPlannerWorkbookScaffoldTests, DocumentAssemblerDocxFeaturesTests? ??????. - README.md? docs/DEVELOPMENT.md? 2026-04-14 22:14 (KST) ?? ?? ??? ??????. ?? ??: - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_planning2\\ -p:IntermediateOutputPath=obj\\verify_doc_planning2\\ : ?? 0 / ?? 0 - dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "DocumentPlannerWorkbookScaffoldTests|DocumentAssemblerDocxFeaturesTests|DocumentAssemblerSemanticTests|DocumentPlannerBusinessDocumentTests|ExcelSkillExecutiveSummaryLinkTests|HtmlSkillConsultingSectionsTests|DocxSkillTemplateFeaturesTests" -p:OutputPath=bin\\verify_doc_planning_tests3\\ -p:IntermediateOutputPath=obj\\verify_doc_planning_tests3\\ : ?? 7
This commit is contained in:
@@ -120,7 +120,7 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
switch (format)
|
||||
{
|
||||
case "docx":
|
||||
resultMsg = AssembleDocx(fullPath, title, sections, headerText, footerText);
|
||||
resultMsg = AssembleDocx(fullPath, title, sections, useToc, coverSubtitle, headerText, footerText);
|
||||
break;
|
||||
case "markdown":
|
||||
resultMsg = AssembleMarkdown(fullPath, title, sections);
|
||||
@@ -231,13 +231,15 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
File.WriteAllText(path, sb.ToString(), Encoding.UTF8);
|
||||
|
||||
var issues = ValidateBasic(sb.ToString());
|
||||
var review = ArtifactQualityReviewService.ReviewHtml(title, sb.ToString(), !string.IsNullOrWhiteSpace(coverSubtitle), toc, printReady: true);
|
||||
var reviewSummary = $" HTML 품질 리뷰: {review.Score}/100 | 강점 {review.Strengths.Count} | 이슈 {review.Issues.Count}";
|
||||
return issues.Count > 0
|
||||
? $" ⚠ 품질 검증 이슈 {issues.Count}건: {string.Join("; ", issues)}"
|
||||
: " ✓ 품질 검증 통과";
|
||||
? $"{reviewSummary} | 기본 검토 이슈 {issues.Count}건: {string.Join("; ", issues)}"
|
||||
: reviewSummary;
|
||||
}
|
||||
|
||||
private string AssembleDocx(string path, string title, List<(string Heading, string Content, int Level)> sections,
|
||||
string? headerText, string? footerText)
|
||||
bool useToc, string? coverSubtitle, string? headerText, string? footerText)
|
||||
{
|
||||
using var doc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Create(
|
||||
path, DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
|
||||
@@ -424,6 +426,74 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
}
|
||||
}
|
||||
|
||||
var includeCover = !string.IsNullOrWhiteSpace(coverSubtitle);
|
||||
if (includeCover)
|
||||
AppendAssemblerCoverPage(body, title, coverSubtitle!);
|
||||
else
|
||||
body.AppendChild(CreateParagraph(title, fontSize: "48", bold: true, color: "1F3A5F"));
|
||||
|
||||
if (!includeCover)
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
|
||||
|
||||
if (useToc && sections.Count > 3)
|
||||
AppendAssemblerTableOfContents(body);
|
||||
|
||||
var tableCount = 0;
|
||||
var listCount = 0;
|
||||
var calloutCount = 0;
|
||||
var highlightCount = 0;
|
||||
var headings = new List<string>();
|
||||
|
||||
foreach (var (heading, content, level) in sections)
|
||||
{
|
||||
var headPara = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
|
||||
var headRun = new DocumentFormat.OpenXml.Wordprocessing.Run();
|
||||
headRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties
|
||||
{
|
||||
RunFonts = KoreanFonts(),
|
||||
Bold = new DocumentFormat.OpenXml.Wordprocessing.Bold(),
|
||||
FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = level <= 1 ? "32" : "28" },
|
||||
Color = new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "2B579A" },
|
||||
});
|
||||
headRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(heading));
|
||||
headPara.AppendChild(headRun);
|
||||
body.AppendChild(headPara);
|
||||
headings.Add(heading);
|
||||
|
||||
AppendStructuredContent(content);
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
|
||||
}
|
||||
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.SectionProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.PageSize { Width = 11906, Height = 16838 },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.PageMargin { Top = 1440, Right = 1440, Bottom = 1440, Left = 1440,
|
||||
Header = 720, Footer = 720, Gutter = 0 }
|
||||
));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(headerText) || !string.IsNullOrWhiteSpace(footerText))
|
||||
AddAssemblerHeaderFooter(mainPart, body, headerText, footerText, showPageNumbers: true);
|
||||
|
||||
mainPart.Document.Save();
|
||||
|
||||
var review = ArtifactQualityReviewService.ReviewStructuredDocument(new StructuredDocumentReviewInput(
|
||||
title,
|
||||
headings.Count,
|
||||
sections.Sum(section => StripHtmlTags(section.Content).Length),
|
||||
tableCount,
|
||||
listCount,
|
||||
calloutCount,
|
||||
highlightCount,
|
||||
0,
|
||||
includeCover,
|
||||
useToc && sections.Count > 3,
|
||||
false,
|
||||
!string.IsNullOrWhiteSpace(headerText) || !string.IsNullOrWhiteSpace(footerText),
|
||||
headings.Any(h => ArtifactQualityReviewService.ContainsBusinessKeyword(h, "executive summary", "summary", "요약")),
|
||||
headings.Any(h => ArtifactQualityReviewService.ContainsBusinessKeyword(h, "recommendation", "proposal", "next step", "action", "권고", "실행")),
|
||||
headings.Any(h => ArtifactQualityReviewService.ContainsBusinessKeyword(h, "appendix", "reference", "supplement", "부록", "참고"))));
|
||||
|
||||
return $" DOCX 품질 리뷰: {review.Score}/100 | 강점 {review.Strengths.Count} | 이슈 {review.Issues.Count}";
|
||||
|
||||
void AppendStructuredContent(string rawContent)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawContent))
|
||||
@@ -437,7 +507,7 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
}
|
||||
|
||||
normalized = Regex.Replace(normalized, @"<br\s*/?>", "\n", RegexOptions.IgnoreCase);
|
||||
var blockPattern = @"<table\b[^>]*>.*?</table>|<ul\b[^>]*>.*?</ul>|<ol\b[^>]*>.*?</ol>|<blockquote\b[^>]*>.*?</blockquote>|<div\b[^>]*class=""[^""]*(callout-[^""]*|comparison-grid|roadmap-block|matrix-grid)[^""]*""[^>]*>.*?</div>|<h[2-6]\b[^>]*>.*?</h[2-6]>|<p\b[^>]*>.*?</p>";
|
||||
var blockPattern = @"<table\b[^>]*>.*?</table>|<ul\b[^>]*>.*?</ul>|<ol\b[^>]*>.*?</ol>|<blockquote\b[^>]*>.*?</blockquote>|<div\b[^>]*class=""[^""]*(callout-[^""]*|comparison-grid|roadmap-block|matrix-grid|highlight-box)[^""]*""[^>]*>.*?</div>|<h[2-6]\b[^>]*>.*?</h[2-6]>|<p\b[^>]*>.*?</p>";
|
||||
var matches = Regex.Matches(normalized, blockPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
if (matches.Count == 0)
|
||||
@@ -459,14 +529,17 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
if (Regex.IsMatch(block, @"^<table", RegexOptions.IgnoreCase))
|
||||
{
|
||||
body.AppendChild(CreateTableFromHtml(block));
|
||||
tableCount++;
|
||||
}
|
||||
else if (Regex.IsMatch(block, @"^<ul", RegexOptions.IgnoreCase))
|
||||
{
|
||||
AppendListBlock(block, ordered: false);
|
||||
listCount++;
|
||||
}
|
||||
else if (Regex.IsMatch(block, @"^<ol", RegexOptions.IgnoreCase))
|
||||
{
|
||||
AppendListBlock(block, ordered: true);
|
||||
listCount++;
|
||||
}
|
||||
else if (Regex.IsMatch(block, @"^<h", RegexOptions.IgnoreCase))
|
||||
{
|
||||
@@ -474,7 +547,12 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
}
|
||||
else if (Regex.IsMatch(block, @"^<(blockquote|div)", RegexOptions.IgnoreCase))
|
||||
{
|
||||
body.AppendChild(CreateParagraph(ExtractStructuredText(block), fontSize: "21", bold: true, color: "1F3A5F", fill: "EDF4FF"));
|
||||
var fill = Regex.IsMatch(block, "highlight-box", RegexOptions.IgnoreCase) ? "FFF7DA" : "EDF4FF";
|
||||
body.AppendChild(CreateParagraph(ExtractStructuredText(block), fontSize: "21", bold: true, color: "1F3A5F", fill: fill));
|
||||
if (Regex.IsMatch(block, "highlight-box", RegexOptions.IgnoreCase))
|
||||
highlightCount++;
|
||||
else
|
||||
calloutCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -487,49 +565,6 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
if (cursor < normalized.Length)
|
||||
AppendPlainText(ExtractStructuredText(normalized[cursor..]));
|
||||
}
|
||||
|
||||
var titlePara = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
|
||||
var titleRun = new DocumentFormat.OpenXml.Wordprocessing.Run();
|
||||
titleRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties
|
||||
{
|
||||
RunFonts = KoreanFonts(),
|
||||
Bold = new DocumentFormat.OpenXml.Wordprocessing.Bold(),
|
||||
FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "48" }
|
||||
});
|
||||
titleRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(title));
|
||||
titlePara.AppendChild(titleRun);
|
||||
body.AppendChild(titlePara);
|
||||
|
||||
// 빈 줄
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
|
||||
|
||||
foreach (var (heading, content, level) in sections)
|
||||
{
|
||||
var headPara = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
|
||||
var headRun = new DocumentFormat.OpenXml.Wordprocessing.Run();
|
||||
headRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties
|
||||
{
|
||||
RunFonts = KoreanFonts(),
|
||||
Bold = new DocumentFormat.OpenXml.Wordprocessing.Bold(),
|
||||
FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = level <= 1 ? "32" : "28" },
|
||||
Color = new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "2B579A" },
|
||||
});
|
||||
headRun.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(heading));
|
||||
headPara.AppendChild(headRun);
|
||||
body.AppendChild(headPara);
|
||||
|
||||
AppendStructuredContent(content);
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
|
||||
}
|
||||
|
||||
body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.SectionProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.PageSize { Width = 11906, Height = 16838 },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.PageMargin { Top = 1440, Right = 1440, Bottom = 1440, Left = 1440,
|
||||
Header = 720, Footer = 720, Gutter = 0 }
|
||||
));
|
||||
|
||||
mainPart.Document.Save();
|
||||
return " ✓ DOCX 조립 완료";
|
||||
}
|
||||
|
||||
/// <summary>DOCX 기본 스타일 정의 생성 (한글 글꼴 기본 설정 포함).</summary>
|
||||
@@ -573,6 +608,235 @@ public class DocumentAssemblerTool : IAgentTool
|
||||
return styles;
|
||||
}
|
||||
|
||||
private static void AppendAssemblerCoverPage(DocumentFormat.OpenXml.Wordprocessing.Body body, string title, string subtitle)
|
||||
{
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties
|
||||
{
|
||||
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification
|
||||
{
|
||||
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Center
|
||||
},
|
||||
SpacingBetweenLines = new DocumentFormat.OpenXml.Wordprocessing.SpacingBetweenLines
|
||||
{
|
||||
Before = "1600",
|
||||
After = "120"
|
||||
}
|
||||
},
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Bold(),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "44" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "1F3A5F" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Text(title))));
|
||||
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties
|
||||
{
|
||||
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification
|
||||
{
|
||||
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Center
|
||||
},
|
||||
SpacingBetweenLines = new DocumentFormat.OpenXml.Wordprocessing.SpacingBetweenLines
|
||||
{
|
||||
After = "260"
|
||||
}
|
||||
},
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "26" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "5B6472" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Text(subtitle))));
|
||||
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties
|
||||
{
|
||||
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification
|
||||
{
|
||||
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Center
|
||||
}
|
||||
},
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "18" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "808080" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Text(DateTime.Now.ToString("yyyy-MM-dd")))));
|
||||
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.Break
|
||||
{
|
||||
Type = DocumentFormat.OpenXml.Wordprocessing.BreakValues.Page
|
||||
})));
|
||||
}
|
||||
|
||||
private static void AppendAssemblerTableOfContents(DocumentFormat.OpenXml.Wordprocessing.Body body)
|
||||
{
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.SpacingBetweenLines { Before = "120", After = "120" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Bold(),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "28" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Text("목차"))));
|
||||
|
||||
var paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
|
||||
paragraph.Append(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.FieldChar
|
||||
{
|
||||
FieldCharType = DocumentFormat.OpenXml.Wordprocessing.FieldCharValues.Begin
|
||||
}));
|
||||
paragraph.Append(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.FieldCode(" TOC \\o \"1-3\" \\h \\z \\u ")
|
||||
{
|
||||
Space = DocumentFormat.OpenXml.SpaceProcessingModeValues.Preserve
|
||||
}));
|
||||
paragraph.Append(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.FieldChar
|
||||
{
|
||||
FieldCharType = DocumentFormat.OpenXml.Wordprocessing.FieldCharValues.Separate
|
||||
}));
|
||||
paragraph.Append(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.Text("Word에서 필드 업데이트를 실행하면 목차가 새로 고쳐집니다.")));
|
||||
paragraph.Append(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.FieldChar
|
||||
{
|
||||
FieldCharType = DocumentFormat.OpenXml.Wordprocessing.FieldCharValues.End
|
||||
}));
|
||||
body.Append(paragraph);
|
||||
body.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.Break
|
||||
{
|
||||
Type = DocumentFormat.OpenXml.Wordprocessing.BreakValues.Page
|
||||
})));
|
||||
}
|
||||
|
||||
private static void AddAssemblerHeaderFooter(
|
||||
DocumentFormat.OpenXml.Packaging.MainDocumentPart mainPart,
|
||||
DocumentFormat.OpenXml.Wordprocessing.Body body,
|
||||
string? headerText,
|
||||
string? footerText,
|
||||
bool showPageNumbers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(headerText))
|
||||
{
|
||||
var headerPart = mainPart.AddNewPart<DocumentFormat.OpenXml.Packaging.HeaderPart>();
|
||||
var header = new DocumentFormat.OpenXml.Wordprocessing.Header();
|
||||
var paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Run(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunProperties(
|
||||
new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "18" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "808080" },
|
||||
new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }),
|
||||
new DocumentFormat.OpenXml.Wordprocessing.Text(headerText)));
|
||||
paragraph.ParagraphProperties = new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties
|
||||
{
|
||||
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification
|
||||
{
|
||||
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Right
|
||||
}
|
||||
};
|
||||
header.Append(paragraph);
|
||||
headerPart.Header = header;
|
||||
|
||||
var sectionProperties = body.Elements<DocumentFormat.OpenXml.Wordprocessing.SectionProperties>().LastOrDefault()
|
||||
?? body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.SectionProperties());
|
||||
sectionProperties.Elements<DocumentFormat.OpenXml.Wordprocessing.HeaderReference>().ToList().ForEach(reference => reference.Remove());
|
||||
sectionProperties.Append(new DocumentFormat.OpenXml.Wordprocessing.HeaderReference
|
||||
{
|
||||
Type = DocumentFormat.OpenXml.Wordprocessing.HeaderFooterValues.Default,
|
||||
Id = mainPart.GetIdOfPart(headerPart)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(footerText) || showPageNumbers)
|
||||
{
|
||||
var footerPart = mainPart.AddNewPart<DocumentFormat.OpenXml.Packaging.FooterPart>();
|
||||
var footer = new DocumentFormat.OpenXml.Wordprocessing.Footer();
|
||||
var paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph
|
||||
{
|
||||
ParagraphProperties = new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties
|
||||
{
|
||||
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification
|
||||
{
|
||||
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Center
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var displayText = string.IsNullOrWhiteSpace(footerText) ? "AX Copilot" : footerText!;
|
||||
if (showPageNumbers)
|
||||
{
|
||||
if (displayText.Contains("{page}", StringComparison.Ordinal))
|
||||
{
|
||||
var parts = displayText.Split("{page}", StringSplitOptions.None);
|
||||
paragraph.Append(CreateAssemblerFooterRun(parts[0]));
|
||||
paragraph.Append(CreateAssemblerPageNumberRun());
|
||||
if (parts.Length > 1)
|
||||
paragraph.Append(CreateAssemblerFooterRun(parts[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
paragraph.Append(CreateAssemblerFooterRun(displayText + " · "));
|
||||
paragraph.Append(CreateAssemblerPageNumberRun());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
paragraph.Append(CreateAssemblerFooterRun(displayText));
|
||||
}
|
||||
|
||||
footer.Append(paragraph);
|
||||
footerPart.Footer = footer;
|
||||
|
||||
var sectionProperties = body.Elements<DocumentFormat.OpenXml.Wordprocessing.SectionProperties>().LastOrDefault()
|
||||
?? body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.SectionProperties());
|
||||
sectionProperties.Elements<DocumentFormat.OpenXml.Wordprocessing.FooterReference>().ToList().ForEach(reference => reference.Remove());
|
||||
sectionProperties.Append(new DocumentFormat.OpenXml.Wordprocessing.FooterReference
|
||||
{
|
||||
Type = DocumentFormat.OpenXml.Wordprocessing.HeaderFooterValues.Default,
|
||||
Id = mainPart.GetIdOfPart(footerPart)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static DocumentFormat.OpenXml.Wordprocessing.Run CreateAssemblerFooterRun(string text) =>
|
||||
new(new DocumentFormat.OpenXml.Wordprocessing.Text(text) { Space = DocumentFormat.OpenXml.SpaceProcessingModeValues.Preserve })
|
||||
{
|
||||
RunProperties = new DocumentFormat.OpenXml.Wordprocessing.RunProperties
|
||||
{
|
||||
FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "16" },
|
||||
Color = new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "999999" },
|
||||
RunFonts = new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }
|
||||
}
|
||||
};
|
||||
|
||||
private static DocumentFormat.OpenXml.Wordprocessing.Run CreateAssemblerPageNumberRun()
|
||||
{
|
||||
var run = new DocumentFormat.OpenXml.Wordprocessing.Run
|
||||
{
|
||||
RunProperties = new DocumentFormat.OpenXml.Wordprocessing.RunProperties
|
||||
{
|
||||
FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize { Val = "16" },
|
||||
Color = new DocumentFormat.OpenXml.Wordprocessing.Color { Val = "999999" },
|
||||
RunFonts = new DocumentFormat.OpenXml.Wordprocessing.RunFonts { Ascii = "맑은 고딕", HighAnsi = "맑은 고딕", EastAsia = "맑은 고딕" }
|
||||
}
|
||||
};
|
||||
|
||||
run.Append(new DocumentFormat.OpenXml.Wordprocessing.FieldChar
|
||||
{
|
||||
FieldCharType = DocumentFormat.OpenXml.Wordprocessing.FieldCharValues.Begin
|
||||
});
|
||||
run.Append(new DocumentFormat.OpenXml.Wordprocessing.FieldCode(" PAGE ")
|
||||
{
|
||||
Space = DocumentFormat.OpenXml.SpaceProcessingModeValues.Preserve
|
||||
});
|
||||
run.Append(new DocumentFormat.OpenXml.Wordprocessing.FieldChar
|
||||
{
|
||||
FieldCharType = DocumentFormat.OpenXml.Wordprocessing.FieldCharValues.End
|
||||
});
|
||||
return run;
|
||||
}
|
||||
|
||||
private string AssembleMarkdown(string path, string title, List<(string Heading, string Content, int Level)> sections)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
Reference in New Issue
Block a user