1237 lines
44 KiB
C#
1237 lines
44 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.Encodings.Web;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using DocumentFormat.OpenXml;
|
|
using DocumentFormat.OpenXml.Packaging;
|
|
using DocumentFormat.OpenXml.Wordprocessing;
|
|
|
|
namespace AxCopilot.Services.Agent;
|
|
|
|
public class DocumentPlannerTool : IAgentTool
|
|
{
|
|
private class SectionPlan
|
|
{
|
|
public string Id { get; set; } = "";
|
|
|
|
public string Heading { get; set; } = "";
|
|
|
|
public int Level { get; set; } = 1;
|
|
|
|
public int TargetWords { get; set; } = 300;
|
|
|
|
public List<string> KeyPoints { get; set; } = new List<string>();
|
|
}
|
|
|
|
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true,
|
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
};
|
|
|
|
public string Name => "document_plan";
|
|
|
|
public string Description => "Create a structured document outline/plan and optionally generate the document file immediately. Use this BEFORE generating long documents (3+ pages). When multi-pass mode is OFF, this tool directly creates and saves a document file with section headings and key points. When multi-pass mode is ON, returns a plan for section-by-section writing via document_assemble.";
|
|
|
|
public ToolParameterSchema Parameters
|
|
{
|
|
get
|
|
{
|
|
ToolParameterSchema toolParameterSchema = new ToolParameterSchema();
|
|
Dictionary<string, ToolProperty> obj = new Dictionary<string, ToolProperty> { ["topic"] = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Document topic or full user request describing what the document should cover."
|
|
} };
|
|
ToolProperty obj2 = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Type of document: report, proposal, analysis, manual, minutes, presentation, guide. Default: report"
|
|
};
|
|
int num = 7;
|
|
List<string> list = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list, num);
|
|
Span<string> span = CollectionsMarshal.AsSpan(list);
|
|
span[0] = "report";
|
|
span[1] = "proposal";
|
|
span[2] = "analysis";
|
|
span[3] = "manual";
|
|
span[4] = "minutes";
|
|
span[5] = "presentation";
|
|
span[6] = "guide";
|
|
obj2.Enum = list;
|
|
obj["document_type"] = obj2;
|
|
obj["target_pages"] = new ToolProperty
|
|
{
|
|
Type = "integer",
|
|
Description = "Target number of pages (1 page ≈ 500 words). Default: 5"
|
|
};
|
|
ToolProperty obj3 = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Output document format: html, docx, markdown. Default: html"
|
|
};
|
|
num = 3;
|
|
List<string> list2 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list2, num);
|
|
Span<string> span2 = CollectionsMarshal.AsSpan(list2);
|
|
span2[0] = "html";
|
|
span2[1] = "docx";
|
|
span2[2] = "markdown";
|
|
obj3.Enum = list2;
|
|
obj["format"] = obj3;
|
|
obj["sections_hint"] = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Optional hint for desired sections/structure (e.g. '서론, 현황분석, 문제점, 개선방안, 결론')"
|
|
};
|
|
obj["reference_summary"] = new ToolProperty
|
|
{
|
|
Type = "string",
|
|
Description = "Optional summary of reference data already read via file_read (to incorporate into plan)"
|
|
};
|
|
toolParameterSchema.Properties = obj;
|
|
num = 1;
|
|
List<string> list3 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list3, num);
|
|
CollectionsMarshal.AsSpan(list3)[0] = "topic";
|
|
toolParameterSchema.Required = list3;
|
|
return toolParameterSchema;
|
|
}
|
|
}
|
|
|
|
private static bool IsMultiPassEnabled()
|
|
{
|
|
return ((!(Application.Current is App app)) ? ((bool?)null) : app.SettingsService?.Settings.Llm.EnableMultiPassDocument) == true;
|
|
}
|
|
|
|
private static string GetFolderDataUsage()
|
|
{
|
|
return ((!(Application.Current is App app)) ? null : app.SettingsService?.Settings.Llm.FolderDataUsage) ?? "none";
|
|
}
|
|
|
|
public Task<ToolResult> ExecuteAsync(JsonElement args, AgentContext context, CancellationToken ct)
|
|
{
|
|
string text = args.GetProperty("topic").GetString() ?? "";
|
|
JsonElement value;
|
|
string docType = (args.TryGetProperty("document_type", out value) ? (value.GetString() ?? "report") : "report");
|
|
JsonElement value2;
|
|
int num = (args.TryGetProperty("target_pages", out value2) ? value2.GetInt32() : 5);
|
|
JsonElement value3;
|
|
string format = (args.TryGetProperty("format", out value3) ? (value3.GetString() ?? "html") : "html");
|
|
JsonElement value4;
|
|
string hint = (args.TryGetProperty("sections_hint", out value4) ? (value4.GetString() ?? "") : "");
|
|
JsonElement value5;
|
|
string refSummary = (args.TryGetProperty("reference_summary", out value5) ? (value5.GetString() ?? "") : "");
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
{
|
|
return Task.FromResult(ToolResult.Fail("topic이 비어있습니다."));
|
|
}
|
|
if (num < 1)
|
|
{
|
|
num = 1;
|
|
}
|
|
if (num > 50)
|
|
{
|
|
num = 50;
|
|
}
|
|
bool flag = IsMultiPassEnabled();
|
|
string folderDataUsage = GetFolderDataUsage();
|
|
int num2 = (flag ? ((int)Math.Ceiling((double)num * 1.5)) : num);
|
|
int totalWords = num2 * 500;
|
|
List<SectionPlan> sections = BuildSections(docType, num2, hint, refSummary);
|
|
DistributeWordCount(sections, totalWords);
|
|
if ((folderDataUsage == "active" || folderDataUsage == "passive") ? true : false)
|
|
{
|
|
return ExecuteSinglePassWithData(text, docType, format, num2, totalWords, sections, folderDataUsage, refSummary);
|
|
}
|
|
return ExecuteWithAssembleInstructions(text, docType, format, num2, totalWords, sections, flag);
|
|
}
|
|
|
|
private Task<ToolResult> ExecuteWithAssembleInstructions(string topic, string docType, string format, int targetPages, int totalWords, List<SectionPlan> sections, bool highQuality)
|
|
{
|
|
string text = SanitizeFileName(topic);
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text2 = ((format == "docx") ? ".docx" : ((!(format == "markdown")) ? ".html" : ".md"));
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text3 = text2;
|
|
string fileName = text + text3;
|
|
string label = (highQuality ? "[고품질]" : "[표준]");
|
|
if (!(format == "markdown"))
|
|
{
|
|
if (format == "docx")
|
|
{
|
|
return ExecuteWithDocxScaffold(topic, fileName, sections, targetPages, totalWords, label);
|
|
}
|
|
return ExecuteWithHtmlScaffold(topic, fileName, sections, targetPages, totalWords, label);
|
|
}
|
|
return ExecuteWithMarkdownScaffold(topic, fileName, sections, targetPages, totalWords, label);
|
|
}
|
|
|
|
private Task<ToolResult> ExecuteWithHtmlScaffold(string topic, string fileName, List<SectionPlan> sections, int targetPages, int totalWords, string label)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
StringBuilder stringBuilder2;
|
|
StringBuilder.AppendInterpolatedStringHandler handler;
|
|
foreach (SectionPlan section in sections)
|
|
{
|
|
string value = SuggestHtmlElements(section.KeyPoints);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder3 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
|
|
handler.AppendLiteral("<h2>");
|
|
handler.AppendFormatted(Escape(section.Heading));
|
|
handler.AppendLiteral("</h2>");
|
|
stringBuilder3.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder4 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(17, 2, stringBuilder2);
|
|
handler.AppendLiteral("<!-- 목표 ");
|
|
handler.AppendFormatted(section.TargetWords);
|
|
handler.AppendLiteral("단어 | 핵심: ");
|
|
handler.AppendFormatted(string.Join(", ", section.KeyPoints));
|
|
stringBuilder4.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder5 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(33, 1, stringBuilder2);
|
|
handler.AppendLiteral(" 활용 가능 요소(내용에 맞게 자유 선택): ");
|
|
handler.AppendFormatted(value);
|
|
handler.AppendLiteral(" -->");
|
|
stringBuilder5.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
}
|
|
StringBuilder stringBuilder6 = new StringBuilder();
|
|
stringBuilder2 = stringBuilder6;
|
|
StringBuilder stringBuilder7 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(30, 4, stringBuilder2);
|
|
handler.AppendLiteral("\ud83d\udccb 문서 개요 생성 완료 ");
|
|
handler.AppendFormatted(label);
|
|
handler.AppendLiteral(" (");
|
|
handler.AppendFormatted(sections.Count);
|
|
handler.AppendLiteral("개 섹션, ");
|
|
handler.AppendFormatted(targetPages);
|
|
handler.AppendLiteral("페이지/");
|
|
handler.AppendFormatted(totalWords);
|
|
handler.AppendLiteral("단어)");
|
|
stringBuilder7.AppendLine(ref handler);
|
|
stringBuilder6.AppendLine();
|
|
stringBuilder6.AppendLine("## 즉시 실행: html_create 호출");
|
|
stringBuilder2 = stringBuilder6;
|
|
StringBuilder stringBuilder8 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2);
|
|
handler.AppendLiteral("path: \"");
|
|
handler.AppendFormatted(fileName);
|
|
handler.AppendLiteral("\"");
|
|
stringBuilder8.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder6;
|
|
StringBuilder stringBuilder9 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
|
|
handler.AppendLiteral("title: \"");
|
|
handler.AppendFormatted(topic);
|
|
handler.AppendLiteral("\"");
|
|
stringBuilder9.AppendLine(ref handler);
|
|
stringBuilder6.AppendLine("toc: true, numbered: true, mood: \"professional\"");
|
|
stringBuilder2 = stringBuilder6;
|
|
StringBuilder stringBuilder10 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(50, 1, stringBuilder2);
|
|
handler.AppendLiteral("cover: {\"title\": \"");
|
|
handler.AppendFormatted(topic);
|
|
handler.AppendLiteral("\", \"author\": \"AX Copilot Agent\"}");
|
|
stringBuilder10.AppendLine(ref handler);
|
|
stringBuilder6.AppendLine();
|
|
stringBuilder6.AppendLine("body에 아래 섹션 구조를 기반으로 각 섹션의 내용과 시각화를 자유롭게 작성하세요:");
|
|
stringBuilder6.AppendLine("(주석의 '활용 가능 요소'는 참고용이며, 내용에 맞게 다른 요소를 써도 됩니다)");
|
|
stringBuilder6.AppendLine();
|
|
stringBuilder6.AppendLine("--- body 시작 ---");
|
|
stringBuilder6.Append(stringBuilder);
|
|
stringBuilder6.AppendLine("--- body 끝 ---");
|
|
stringBuilder6.AppendLine();
|
|
stringBuilder6.AppendLine("⚠ html_create를 지금 즉시 호출하세요. 모든 섹션에 충분한 실제 내용을 작성하세요.");
|
|
return Task.FromResult(ToolResult.Ok(stringBuilder6.ToString()));
|
|
}
|
|
|
|
private static string SuggestHtmlElements(List<string> keyPoints)
|
|
{
|
|
string text = string.Join(" ", keyPoints).ToLowerInvariant();
|
|
List<string> list = new List<string>();
|
|
if (ContainsAny(text, "매출", "실적", "통계", "수치", "비교", "현황", "지표", "점유율", "비율", "순위", "성과"))
|
|
{
|
|
list.Add("table(데이터 정리)");
|
|
list.Add("div.chart-bar(수치 시각화)");
|
|
}
|
|
if (ContainsAny(text, "강점", "약점", "기회", "위협", "swot", "리스크", "문제점", "장점", "단점"))
|
|
{
|
|
list.Add("div.grid-2(항목 대비)");
|
|
list.Add("callout-warning/callout-tip");
|
|
}
|
|
if (ContainsAny(text, "전략", "제안", "방안", "계획", "방향", "로드맵", "목표"))
|
|
{
|
|
list.Add("callout-info(핵심 전략)");
|
|
list.Add("span.badge-blue/green(구분 배지)");
|
|
}
|
|
if (ContainsAny(text, "일정", "단계", "절차", "프로세스", "과정", "순서", "연혁", "역사"))
|
|
{
|
|
list.Add("div.timeline(단계/일정)");
|
|
}
|
|
if (ContainsAny(text, "달성", "진행", "완료", "목표 대비", "진척"))
|
|
{
|
|
list.Add("div.progress(달성률)");
|
|
}
|
|
if (ContainsAny(text, "종류", "유형", "분류", "구성", "항목", "요소", "구분"))
|
|
{
|
|
list.Add("div.grid-3.card(항목 카드)");
|
|
}
|
|
if (ContainsAny(text, "핵심", "요약", "결론", "시사점", "포인트"))
|
|
{
|
|
list.Add("blockquote(핵심 메시지)");
|
|
}
|
|
list.Add("p/ul/ol(일반 서술)");
|
|
return string.Join(" | ", list.Distinct().Take(4));
|
|
}
|
|
|
|
private static bool ContainsAny(string text, params string[] keywords)
|
|
{
|
|
return keywords.Any((string k) => text.Contains(k));
|
|
}
|
|
|
|
private Task<ToolResult> ExecuteWithDocxScaffold(string topic, string fileName, List<SectionPlan> sections, int targetPages, int totalWords, string label)
|
|
{
|
|
var sections2 = sections.Select((SectionPlan s) => new
|
|
{
|
|
heading = s.Heading,
|
|
content = $"[{s.Heading} 내용을 {s.TargetWords}단어 이상으로 작성. 핵심 항목: {string.Join(", ", s.KeyPoints)}]",
|
|
level = s.Level
|
|
});
|
|
string value = JsonSerializer.Serialize(new
|
|
{
|
|
path = fileName,
|
|
title = topic,
|
|
format = "docx",
|
|
cover_subtitle = "AX Copilot Agent",
|
|
sections = sections2
|
|
}, _jsonOptions);
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
StringBuilder stringBuilder2 = stringBuilder;
|
|
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(30, 4, stringBuilder2);
|
|
handler.AppendLiteral("\ud83d\udccb 문서 개요 생성 완료 ");
|
|
handler.AppendFormatted(label);
|
|
handler.AppendLiteral(" (");
|
|
handler.AppendFormatted(sections.Count);
|
|
handler.AppendLiteral("개 섹션, ");
|
|
handler.AppendFormatted(targetPages);
|
|
handler.AppendLiteral("페이지/");
|
|
handler.AppendFormatted(totalWords);
|
|
handler.AppendLiteral("단어)");
|
|
stringBuilder2.AppendLine(ref handler);
|
|
stringBuilder.AppendLine("아래 document_assemble 파라미터에서 각 sections[].content의 [내용...] 부분을 실제 내용으로 채워서 즉시 호출하세요.");
|
|
stringBuilder.AppendLine();
|
|
stringBuilder.AppendLine("## 즉시 실행: document_assemble 호출 파라미터");
|
|
stringBuilder.AppendLine(value);
|
|
stringBuilder.AppendLine("⚠ 주의: 설명하지 말고 document_assemble 도구를 지금 즉시 호출하세요.");
|
|
return Task.FromResult(ToolResult.Ok(stringBuilder.ToString()));
|
|
}
|
|
|
|
private Task<ToolResult> ExecuteWithMarkdownScaffold(string topic, string fileName, List<SectionPlan> sections, int targetPages, int totalWords, string label)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
StringBuilder stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder3 = stringBuilder2;
|
|
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
|
|
handler.AppendLiteral("# ");
|
|
handler.AppendFormatted(topic);
|
|
stringBuilder3.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder4 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
|
|
handler.AppendLiteral("*작성일: ");
|
|
handler.AppendFormatted(DateTime.Now, "yyyy-MM-dd");
|
|
handler.AppendLiteral("*");
|
|
stringBuilder4.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
foreach (SectionPlan section in sections)
|
|
{
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder5 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
|
|
handler.AppendLiteral("## ");
|
|
handler.AppendFormatted(section.Heading);
|
|
stringBuilder5.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder6 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(21, 2, stringBuilder2);
|
|
handler.AppendLiteral("<!-- 목표 ");
|
|
handler.AppendFormatted(section.TargetWords);
|
|
handler.AppendLiteral("단어 | 핵심: ");
|
|
handler.AppendFormatted(string.Join(" / ", section.KeyPoints));
|
|
handler.AppendLiteral(" -->");
|
|
stringBuilder6.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder7 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(24, 2, stringBuilder2);
|
|
handler.AppendLiteral("[");
|
|
handler.AppendFormatted(section.Heading);
|
|
handler.AppendLiteral(" 내용을 ");
|
|
handler.AppendFormatted(section.TargetWords);
|
|
handler.AppendLiteral("단어 이상으로 상세히 작성하세요]");
|
|
stringBuilder7.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
}
|
|
StringBuilder stringBuilder8 = new StringBuilder();
|
|
stringBuilder2 = stringBuilder8;
|
|
StringBuilder stringBuilder9 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(30, 4, stringBuilder2);
|
|
handler.AppendLiteral("\ud83d\udccb 문서 개요 생성 완료 ");
|
|
handler.AppendFormatted(label);
|
|
handler.AppendLiteral(" (");
|
|
handler.AppendFormatted(sections.Count);
|
|
handler.AppendLiteral("개 섹션, ");
|
|
handler.AppendFormatted(targetPages);
|
|
handler.AppendLiteral("페이지/");
|
|
handler.AppendFormatted(totalWords);
|
|
handler.AppendLiteral("단어)");
|
|
stringBuilder9.AppendLine(ref handler);
|
|
stringBuilder8.AppendLine("아래 file_write 파라미터에서 각 섹션의 [내용...] 부분을 실제 내용으로 채워서 즉시 호출하세요.");
|
|
stringBuilder8.AppendLine();
|
|
stringBuilder8.AppendLine("## 즉시 실행: file_write 호출");
|
|
stringBuilder2 = stringBuilder8;
|
|
StringBuilder stringBuilder10 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2);
|
|
handler.AppendLiteral("- path: \"");
|
|
handler.AppendFormatted(fileName);
|
|
handler.AppendLiteral("\"");
|
|
stringBuilder10.AppendLine(ref handler);
|
|
stringBuilder8.AppendLine("- content (각 [내용...] 부분을 실제 내용으로 교체):");
|
|
stringBuilder8.AppendLine(stringBuilder.ToString());
|
|
stringBuilder8.AppendLine("⚠ 주의: 설명하지 말고 file_write 도구를 지금 즉시 호출하세요. 모든 섹션에 실제 내용을 작성하세요.");
|
|
return Task.FromResult(ToolResult.Ok(stringBuilder8.ToString()));
|
|
}
|
|
|
|
private Task<ToolResult> ExecuteSinglePassWithData(string topic, string docType, string format, int targetPages, int totalWords, List<SectionPlan> sections, string folderDataUsage, string refSummary)
|
|
{
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text = ((format == "docx") ? ".docx" : ((!(format == "markdown")) ? ".html" : ".md"));
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text2 = text;
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
text = ((format == "docx") ? "docx_create" : ((!(format == "markdown")) ? "html_create" : "file_write"));
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string value = text;
|
|
string text3 = SanitizeFileName(topic);
|
|
string text4 = text3 + text2;
|
|
bool flag = !string.IsNullOrWhiteSpace(refSummary);
|
|
var value2 = new
|
|
{
|
|
topic = topic,
|
|
document_type = docType,
|
|
format = format,
|
|
target_pages = targetPages,
|
|
estimated_total_words = totalWords,
|
|
suggested_file_name = text4,
|
|
sections = sections,
|
|
reference_data = (flag ? refSummary : null),
|
|
instructions = new
|
|
{
|
|
mode = "single-pass-with-data",
|
|
folder_data_usage = folderDataUsage,
|
|
step1 = (flag ? "Reference data is already provided above. Skip to step 3." : "Use folder_map to scan the work folder, then use document_read to read RELEVANT files only."),
|
|
step2 = (flag ? "(skipped)" : "Summarize the key findings from the folder documents relevant to the topic."),
|
|
step3 = "Write the COMPLETE document content covering ALL sections above, incorporating folder data.",
|
|
step4 = $"Save the document using {value} with the path '{text4}'. " + "Write ALL sections in a SINGLE tool call. Do NOT split into multiple calls.",
|
|
note = "Minimize LLM calls. Read data → write complete document → save. Maximum 3 iterations."
|
|
}
|
|
};
|
|
string value3 = JsonSerializer.Serialize(value2, _jsonOptions);
|
|
string value4 = (flag ? "참조 데이터가 이미 제공되었습니다. 바로 문서를 작성하세요." : ("폴더 데이터 활용 모드(" + folderDataUsage + ")가 활성화되어 있습니다. 먼저 관련 데이터를 읽은 후 문서를 작성하세요."));
|
|
return Task.FromResult(ToolResult.Ok($"\ud83d\udccb 문서 개요가 생성되었습니다 [싱글패스+데이터활용] ({sections.Count}개 섹션, 목표 {targetPages}페이지/{totalWords}단어).\n{value4}\n작성 완료 후 {value}로 '{text4}' 파일에 저장하세요.\n\n{value3}"));
|
|
}
|
|
|
|
private static void GenerateHtml(string path, string title, string docType, List<SectionPlan> sections)
|
|
{
|
|
string css = TemplateService.GetCss("professional");
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
stringBuilder.AppendLine("<!DOCTYPE html>");
|
|
stringBuilder.AppendLine("<html lang=\"ko\">");
|
|
stringBuilder.AppendLine("<head>");
|
|
stringBuilder.AppendLine("<meta charset=\"utf-8\">");
|
|
StringBuilder stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder3 = stringBuilder2;
|
|
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(15, 1, stringBuilder2);
|
|
handler.AppendLiteral("<title>");
|
|
handler.AppendFormatted(Escape(title));
|
|
handler.AppendLiteral("</title>");
|
|
stringBuilder3.AppendLine(ref handler);
|
|
stringBuilder.AppendLine("<style>");
|
|
stringBuilder.AppendLine(css);
|
|
stringBuilder.AppendLine("\n.doc { max-width: 900px; margin: 0 auto; padding: 40px 30px 60px; }\n.doc h1 { font-size: 28px; margin-bottom: 8px; border-bottom: 3px solid var(--accent, #4B5EFC); padding-bottom: 10px; }\n.doc h2 { font-size: 22px; margin-top: 36px; margin-bottom: 12px; border-bottom: 2px solid var(--accent, #4B5EFC); padding-bottom: 6px; }\n.doc .meta { color: #888; font-size: 13px; margin-bottom: 24px; }\n.doc .section { line-height: 1.8; margin-bottom: 20px; }\n.doc .toc { background: #f8f9fa; border-radius: 12px; padding: 20px 28px; margin: 24px 0 32px; }\n.doc .toc h3 { margin-top: 0; }\n.doc .toc a { color: inherit; text-decoration: none; }\n.doc .toc a:hover { text-decoration: underline; }\n.doc .toc ul { list-style: none; padding-left: 0; }\n.doc .toc li { padding: 4px 0; }\n.doc .key-point { background: #f0f4ff; border-left: 4px solid var(--accent, #4B5EFC); padding: 12px 16px; margin: 12px 0; border-radius: 0 8px 8px 0; }\n@media print { .doc h2 { page-break-before: auto; } }\n");
|
|
stringBuilder.AppendLine("</style>");
|
|
stringBuilder.AppendLine("</head>");
|
|
stringBuilder.AppendLine("<body>");
|
|
stringBuilder.AppendLine("<div class=\"doc\">");
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder4 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
|
|
handler.AppendLiteral("<h1>");
|
|
handler.AppendFormatted(Escape(title));
|
|
handler.AppendLiteral("</h1>");
|
|
stringBuilder4.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder5 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(47, 3, stringBuilder2);
|
|
handler.AppendLiteral("<div class=\"meta\">문서 유형: ");
|
|
handler.AppendFormatted(Escape(GetDocTypeLabel(docType)));
|
|
handler.AppendLiteral(" | 작성일: ");
|
|
handler.AppendFormatted(DateTime.Now, "yyyy-MM-dd");
|
|
handler.AppendLiteral(" | 섹션: ");
|
|
handler.AppendFormatted(sections.Count);
|
|
handler.AppendLiteral("개</div>");
|
|
stringBuilder5.AppendLine(ref handler);
|
|
if (sections.Count > 1)
|
|
{
|
|
stringBuilder.AppendLine("<div class=\"toc\">");
|
|
stringBuilder.AppendLine("<h3>\ud83d\udccb 목차</h3>");
|
|
stringBuilder.AppendLine("<ul>");
|
|
for (int i = 0; i < sections.Count; i++)
|
|
{
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder6 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(29, 2, stringBuilder2);
|
|
handler.AppendLiteral("<li><a href=\"#sec-");
|
|
handler.AppendFormatted(i + 1);
|
|
handler.AppendLiteral("\">");
|
|
handler.AppendFormatted(Escape(sections[i].Heading));
|
|
handler.AppendLiteral("</a></li>");
|
|
stringBuilder6.AppendLine(ref handler);
|
|
}
|
|
stringBuilder.AppendLine("</ul>");
|
|
stringBuilder.AppendLine("</div>");
|
|
}
|
|
for (int j = 0; j < sections.Count; j++)
|
|
{
|
|
SectionPlan sectionPlan = sections[j];
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder7 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(19, 2, stringBuilder2);
|
|
handler.AppendLiteral("<h2 id=\"sec-");
|
|
handler.AppendFormatted(j + 1);
|
|
handler.AppendLiteral("\">");
|
|
handler.AppendFormatted(Escape(sectionPlan.Heading));
|
|
handler.AppendLiteral("</h2>");
|
|
stringBuilder7.AppendLine(ref handler);
|
|
stringBuilder.AppendLine("<div class=\"section\">");
|
|
foreach (string keyPoint in sectionPlan.KeyPoints)
|
|
{
|
|
stringBuilder.AppendLine("<div class=\"key-point\">");
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder8 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
|
|
handler.AppendLiteral("<strong>▸ ");
|
|
handler.AppendFormatted(Escape(keyPoint));
|
|
handler.AppendLiteral("</strong>");
|
|
stringBuilder8.AppendLine(ref handler);
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder9 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(40, 2, stringBuilder2);
|
|
handler.AppendLiteral("<p>");
|
|
handler.AppendFormatted(Escape(keyPoint));
|
|
handler.AppendLiteral("에 대한 상세 내용을 여기에 작성합니다. (목표: 약 ");
|
|
handler.AppendFormatted(sectionPlan.TargetWords / Math.Max(1, sectionPlan.KeyPoints.Count));
|
|
handler.AppendLiteral("단어)</p>");
|
|
stringBuilder9.AppendLine(ref handler);
|
|
stringBuilder.AppendLine("</div>");
|
|
}
|
|
stringBuilder.AppendLine("</div>");
|
|
}
|
|
stringBuilder.AppendLine("</div>");
|
|
stringBuilder.AppendLine("</body>");
|
|
stringBuilder.AppendLine("</html>");
|
|
File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8);
|
|
}
|
|
|
|
private static void GenerateDocx(string path, string title, List<SectionPlan> sections)
|
|
{
|
|
using WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Create(path, WordprocessingDocumentType.Document);
|
|
MainDocumentPart mainDocumentPart = wordprocessingDocument.AddMainDocumentPart();
|
|
mainDocumentPart.Document = new Document();
|
|
Body body = mainDocumentPart.Document.AppendChild(new Body());
|
|
AddDocxParagraph(body, title, bold: true, "48");
|
|
AddDocxParagraph(body, $"작성일: {DateTime.Now:yyyy-MM-dd}", bold: false, "20", "888888");
|
|
AddDocxParagraph(body, "");
|
|
foreach (SectionPlan section in sections)
|
|
{
|
|
AddDocxParagraph(body, section.Heading, bold: true, "32", "2B579A");
|
|
foreach (string keyPoint in section.KeyPoints)
|
|
{
|
|
AddDocxParagraph(body, "▸ " + keyPoint, bold: true);
|
|
AddDocxParagraph(body, keyPoint + "에 대한 상세 내용을 여기에 작성합니다.");
|
|
}
|
|
AddDocxParagraph(body, "");
|
|
}
|
|
}
|
|
|
|
private static void AddDocxParagraph(Body body, string text, bool bold = false, string fontSize = "22", string? color = null)
|
|
{
|
|
Paragraph paragraph = new Paragraph();
|
|
Run run = new Run();
|
|
RunProperties runProperties = new RunProperties
|
|
{
|
|
FontSize = new FontSize
|
|
{
|
|
Val = fontSize
|
|
}
|
|
};
|
|
if (bold)
|
|
{
|
|
runProperties.Bold = new Bold();
|
|
}
|
|
if (color != null)
|
|
{
|
|
runProperties.Color = new Color
|
|
{
|
|
Val = color
|
|
};
|
|
}
|
|
run.AppendChild(runProperties);
|
|
run.AppendChild(new Text(text)
|
|
{
|
|
Space = SpaceProcessingModeValues.Preserve
|
|
});
|
|
paragraph.AppendChild(run);
|
|
body.AppendChild(paragraph);
|
|
}
|
|
|
|
private static void GenerateMarkdown(string path, string title, List<SectionPlan> sections)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
StringBuilder stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder3 = stringBuilder2;
|
|
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
|
|
handler.AppendLiteral("# ");
|
|
handler.AppendFormatted(title);
|
|
stringBuilder3.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder4 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
|
|
handler.AppendLiteral("*작성일: ");
|
|
handler.AppendFormatted(DateTime.Now, "yyyy-MM-dd");
|
|
handler.AppendLiteral("*");
|
|
stringBuilder4.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
if (sections.Count > 1)
|
|
{
|
|
stringBuilder.AppendLine("## 목차");
|
|
stringBuilder.AppendLine();
|
|
foreach (SectionPlan section in sections)
|
|
{
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder5 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(7, 2, stringBuilder2);
|
|
handler.AppendLiteral("- [");
|
|
handler.AppendFormatted(section.Heading);
|
|
handler.AppendLiteral("](#");
|
|
handler.AppendFormatted(section.Heading.Replace(" ", "-").ToLowerInvariant());
|
|
handler.AppendLiteral(")");
|
|
stringBuilder5.AppendLine(ref handler);
|
|
}
|
|
stringBuilder.AppendLine();
|
|
stringBuilder.AppendLine("---");
|
|
stringBuilder.AppendLine();
|
|
}
|
|
foreach (SectionPlan section2 in sections)
|
|
{
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder6 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
|
|
handler.AppendLiteral("## ");
|
|
handler.AppendFormatted(section2.Heading);
|
|
stringBuilder6.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
foreach (string keyPoint in section2.KeyPoints)
|
|
{
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder7 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(6, 1, stringBuilder2);
|
|
handler.AppendLiteral("### ▸ ");
|
|
handler.AppendFormatted(keyPoint);
|
|
stringBuilder7.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
stringBuilder2 = stringBuilder;
|
|
StringBuilder stringBuilder8 = stringBuilder2;
|
|
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder2);
|
|
handler.AppendFormatted(keyPoint);
|
|
handler.AppendLiteral("에 대한 상세 내용을 여기에 작성합니다.");
|
|
stringBuilder8.AppendLine(ref handler);
|
|
stringBuilder.AppendLine();
|
|
}
|
|
}
|
|
File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8);
|
|
}
|
|
|
|
private static List<SectionPlan> BuildSections(string docType, int pages, string hint, string refSummary)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(hint))
|
|
{
|
|
string[] array = hint.Split(new char[4] { ',', '/', '→', '\n' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
List<SectionPlan> list = new List<SectionPlan>();
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
SectionPlan obj = new SectionPlan
|
|
{
|
|
Id = $"sec-{i + 1}",
|
|
Heading = $"{i + 1}. {array[i].TrimStart("0123456789. ".ToCharArray())}",
|
|
Level = 1
|
|
};
|
|
int num = 1;
|
|
List<string> list2 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list2, num);
|
|
CollectionsMarshal.AsSpan(list2)[0] = array[i] + " 관련 핵심 내용을 상세히 작성";
|
|
obj.KeyPoints = list2;
|
|
list.Add(obj);
|
|
}
|
|
return list;
|
|
}
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
List<SectionPlan> result;
|
|
switch (docType)
|
|
{
|
|
case "proposal":
|
|
{
|
|
List<SectionPlan> list29 = new List<SectionPlan>();
|
|
SectionPlan obj24 = new SectionPlan
|
|
{
|
|
Id = "sec-1",
|
|
Heading = "1. 개요",
|
|
Level = 1
|
|
};
|
|
int num = 3;
|
|
List<string> list30 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list30, num);
|
|
Span<string> span23 = CollectionsMarshal.AsSpan(list30);
|
|
span23[0] = "배경";
|
|
span23[1] = "목적";
|
|
span23[2] = "범위";
|
|
obj24.KeyPoints = list30;
|
|
list29.Add(obj24);
|
|
SectionPlan obj25 = new SectionPlan
|
|
{
|
|
Id = "sec-2",
|
|
Heading = "2. 현황 분석",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list31 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list31, num);
|
|
Span<string> span24 = CollectionsMarshal.AsSpan(list31);
|
|
span24[0] = "현재 상황";
|
|
span24[1] = "문제점 식별";
|
|
obj25.KeyPoints = list31;
|
|
list29.Add(obj25);
|
|
SectionPlan obj26 = new SectionPlan
|
|
{
|
|
Id = "sec-3",
|
|
Heading = "3. 제안 내용",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list32 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list32, num);
|
|
Span<string> span25 = CollectionsMarshal.AsSpan(list32);
|
|
span25[0] = "핵심 제안";
|
|
span25[1] = "기대 효과";
|
|
span25[2] = "실행 방안";
|
|
obj26.KeyPoints = list32;
|
|
list29.Add(obj26);
|
|
SectionPlan obj27 = new SectionPlan
|
|
{
|
|
Id = "sec-4",
|
|
Heading = "4. 추진 일정",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list33 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list33, num);
|
|
Span<string> span26 = CollectionsMarshal.AsSpan(list33);
|
|
span26[0] = "단계별 일정";
|
|
span26[1] = "마일스톤";
|
|
obj27.KeyPoints = list33;
|
|
list29.Add(obj27);
|
|
SectionPlan obj28 = new SectionPlan
|
|
{
|
|
Id = "sec-5",
|
|
Heading = "5. 소요 자원",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list34 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list34, num);
|
|
Span<string> span27 = CollectionsMarshal.AsSpan(list34);
|
|
span27[0] = "인력";
|
|
span27[1] = "예산";
|
|
span27[2] = "장비";
|
|
obj28.KeyPoints = list34;
|
|
list29.Add(obj28);
|
|
SectionPlan obj29 = new SectionPlan
|
|
{
|
|
Id = "sec-6",
|
|
Heading = "6. 기대 효과 및 결론",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list35 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list35, num);
|
|
Span<string> span28 = CollectionsMarshal.AsSpan(list35);
|
|
span28[0] = "정량적 효과";
|
|
span28[1] = "정성적 효과";
|
|
span28[2] = "결론";
|
|
obj29.KeyPoints = list35;
|
|
list29.Add(obj29);
|
|
result = list29;
|
|
break;
|
|
}
|
|
case "analysis":
|
|
{
|
|
List<SectionPlan> list22 = new List<SectionPlan>();
|
|
SectionPlan obj18 = new SectionPlan
|
|
{
|
|
Id = "sec-1",
|
|
Heading = "1. 분석 개요",
|
|
Level = 1
|
|
};
|
|
int num = 3;
|
|
List<string> list23 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list23, num);
|
|
Span<string> span17 = CollectionsMarshal.AsSpan(list23);
|
|
span17[0] = "분석 목적";
|
|
span17[1] = "분석 범위";
|
|
span17[2] = "방법론";
|
|
obj18.KeyPoints = list23;
|
|
list22.Add(obj18);
|
|
SectionPlan obj19 = new SectionPlan
|
|
{
|
|
Id = "sec-2",
|
|
Heading = "2. 데이터 현황",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list24 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list24, num);
|
|
Span<string> span18 = CollectionsMarshal.AsSpan(list24);
|
|
span18[0] = "데이터 출처";
|
|
span18[1] = "기본 통계";
|
|
span18[2] = "데이터 품질";
|
|
obj19.KeyPoints = list24;
|
|
list22.Add(obj19);
|
|
SectionPlan obj20 = new SectionPlan
|
|
{
|
|
Id = "sec-3",
|
|
Heading = "3. 정량 분석",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list25 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list25, num);
|
|
Span<string> span19 = CollectionsMarshal.AsSpan(list25);
|
|
span19[0] = "수치 분석";
|
|
span19[1] = "추세";
|
|
span19[2] = "비교";
|
|
obj20.KeyPoints = list25;
|
|
list22.Add(obj20);
|
|
SectionPlan obj21 = new SectionPlan
|
|
{
|
|
Id = "sec-4",
|
|
Heading = "4. 정성 분석",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list26 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list26, num);
|
|
Span<string> span20 = CollectionsMarshal.AsSpan(list26);
|
|
span20[0] = "패턴";
|
|
span20[1] = "인사이트";
|
|
span20[2] = "이상치";
|
|
obj21.KeyPoints = list26;
|
|
list22.Add(obj21);
|
|
SectionPlan obj22 = new SectionPlan
|
|
{
|
|
Id = "sec-5",
|
|
Heading = "5. 종합 해석",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list27 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list27, num);
|
|
Span<string> span21 = CollectionsMarshal.AsSpan(list27);
|
|
span21[0] = "핵심 발견";
|
|
span21[1] = "시사점";
|
|
obj22.KeyPoints = list27;
|
|
list22.Add(obj22);
|
|
SectionPlan obj23 = new SectionPlan
|
|
{
|
|
Id = "sec-6",
|
|
Heading = "6. 결론 및 권장사항",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list28 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list28, num);
|
|
Span<string> span22 = CollectionsMarshal.AsSpan(list28);
|
|
span22[0] = "결론";
|
|
span22[1] = "조치 방안";
|
|
span22[2] = "추가 분석 필요 항목";
|
|
obj23.KeyPoints = list28;
|
|
list22.Add(obj23);
|
|
result = list22;
|
|
break;
|
|
}
|
|
case "manual":
|
|
case "guide":
|
|
{
|
|
List<SectionPlan> list16 = new List<SectionPlan>();
|
|
SectionPlan obj13 = new SectionPlan
|
|
{
|
|
Id = "sec-1",
|
|
Heading = "1. 소개",
|
|
Level = 1
|
|
};
|
|
int num = 3;
|
|
List<string> list17 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list17, num);
|
|
Span<string> span12 = CollectionsMarshal.AsSpan(list17);
|
|
span12[0] = "목적";
|
|
span12[1] = "대상 독자";
|
|
span12[2] = "사전 요구사항";
|
|
obj13.KeyPoints = list17;
|
|
list16.Add(obj13);
|
|
SectionPlan obj14 = new SectionPlan
|
|
{
|
|
Id = "sec-2",
|
|
Heading = "2. 시작하기",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list18 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list18, num);
|
|
Span<string> span13 = CollectionsMarshal.AsSpan(list18);
|
|
span13[0] = "설치";
|
|
span13[1] = "초기 설정";
|
|
span13[2] = "기본 사용법";
|
|
obj14.KeyPoints = list18;
|
|
list16.Add(obj14);
|
|
SectionPlan obj15 = new SectionPlan
|
|
{
|
|
Id = "sec-3",
|
|
Heading = "3. 주요 기능",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list19 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list19, num);
|
|
Span<string> span14 = CollectionsMarshal.AsSpan(list19);
|
|
span14[0] = "기능별 상세 설명";
|
|
span14[1] = "사용 예시";
|
|
obj15.KeyPoints = list19;
|
|
list16.Add(obj15);
|
|
SectionPlan obj16 = new SectionPlan
|
|
{
|
|
Id = "sec-4",
|
|
Heading = "4. 고급 기능",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list20 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list20, num);
|
|
Span<string> span15 = CollectionsMarshal.AsSpan(list20);
|
|
span15[0] = "고급 설정";
|
|
span15[1] = "커스터마이징";
|
|
span15[2] = "자동화";
|
|
obj16.KeyPoints = list20;
|
|
list16.Add(obj16);
|
|
SectionPlan obj17 = new SectionPlan
|
|
{
|
|
Id = "sec-5",
|
|
Heading = "5. 문제 해결",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list21 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list21, num);
|
|
Span<string> span16 = CollectionsMarshal.AsSpan(list21);
|
|
span16[0] = "자주 묻는 질문";
|
|
span16[1] = "에러 대응";
|
|
span16[2] = "지원 정보";
|
|
obj17.KeyPoints = list21;
|
|
list16.Add(obj17);
|
|
result = list16;
|
|
break;
|
|
}
|
|
case "minutes":
|
|
{
|
|
List<SectionPlan> list10 = new List<SectionPlan>();
|
|
SectionPlan obj8 = new SectionPlan
|
|
{
|
|
Id = "sec-1",
|
|
Heading = "1. 회의 정보",
|
|
Level = 1
|
|
};
|
|
int num = 3;
|
|
List<string> list11 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list11, num);
|
|
Span<string> span7 = CollectionsMarshal.AsSpan(list11);
|
|
span7[0] = "일시";
|
|
span7[1] = "참석자";
|
|
span7[2] = "장소";
|
|
obj8.KeyPoints = list11;
|
|
list10.Add(obj8);
|
|
SectionPlan obj9 = new SectionPlan
|
|
{
|
|
Id = "sec-2",
|
|
Heading = "2. 안건 및 논의",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list12 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list12, num);
|
|
Span<string> span8 = CollectionsMarshal.AsSpan(list12);
|
|
span8[0] = "안건별 논의 내용";
|
|
span8[1] = "주요 의견";
|
|
obj9.KeyPoints = list12;
|
|
list10.Add(obj9);
|
|
SectionPlan obj10 = new SectionPlan
|
|
{
|
|
Id = "sec-3",
|
|
Heading = "3. 결정 사항",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list13 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list13, num);
|
|
Span<string> span9 = CollectionsMarshal.AsSpan(list13);
|
|
span9[0] = "합의 내용";
|
|
span9[1] = "변경 사항";
|
|
obj10.KeyPoints = list13;
|
|
list10.Add(obj10);
|
|
SectionPlan obj11 = new SectionPlan
|
|
{
|
|
Id = "sec-4",
|
|
Heading = "4. 액션 아이템",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list14 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list14, num);
|
|
Span<string> span10 = CollectionsMarshal.AsSpan(list14);
|
|
span10[0] = "담당자";
|
|
span10[1] = "기한";
|
|
span10[2] = "세부 내용";
|
|
obj11.KeyPoints = list14;
|
|
list10.Add(obj11);
|
|
SectionPlan obj12 = new SectionPlan
|
|
{
|
|
Id = "sec-5",
|
|
Heading = "5. 다음 회의",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list15 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list15, num);
|
|
Span<string> span11 = CollectionsMarshal.AsSpan(list15);
|
|
span11[0] = "예정일";
|
|
span11[1] = "주요 안건";
|
|
obj12.KeyPoints = list15;
|
|
list10.Add(obj12);
|
|
result = list10;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
List<SectionPlan> list3 = new List<SectionPlan>();
|
|
SectionPlan obj2 = new SectionPlan
|
|
{
|
|
Id = "sec-1",
|
|
Heading = "1. 개요",
|
|
Level = 1
|
|
};
|
|
int num = 3;
|
|
List<string> list4 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list4, num);
|
|
Span<string> span = CollectionsMarshal.AsSpan(list4);
|
|
span[0] = "배경";
|
|
span[1] = "목적";
|
|
span[2] = "범위";
|
|
obj2.KeyPoints = list4;
|
|
list3.Add(obj2);
|
|
SectionPlan obj3 = new SectionPlan
|
|
{
|
|
Id = "sec-2",
|
|
Heading = "2. 현황",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list5 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list5, num);
|
|
Span<string> span2 = CollectionsMarshal.AsSpan(list5);
|
|
span2[0] = "현재 상태";
|
|
span2[1] = "주요 지표";
|
|
obj3.KeyPoints = list5;
|
|
list3.Add(obj3);
|
|
SectionPlan obj4 = new SectionPlan
|
|
{
|
|
Id = "sec-3",
|
|
Heading = "3. 분석",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list6 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list6, num);
|
|
Span<string> span3 = CollectionsMarshal.AsSpan(list6);
|
|
span3[0] = "데이터 분석";
|
|
span3[1] = "비교";
|
|
span3[2] = "추세";
|
|
obj4.KeyPoints = list6;
|
|
list3.Add(obj4);
|
|
SectionPlan obj5 = new SectionPlan
|
|
{
|
|
Id = "sec-4",
|
|
Heading = "4. 주요 발견",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list7 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list7, num);
|
|
Span<string> span4 = CollectionsMarshal.AsSpan(list7);
|
|
span4[0] = "핵심 인사이트";
|
|
span4[1] = "문제점";
|
|
span4[2] = "기회";
|
|
obj5.KeyPoints = list7;
|
|
list3.Add(obj5);
|
|
SectionPlan obj6 = new SectionPlan
|
|
{
|
|
Id = "sec-5",
|
|
Heading = "5. 제안",
|
|
Level = 1
|
|
};
|
|
num = 2;
|
|
List<string> list8 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list8, num);
|
|
Span<string> span5 = CollectionsMarshal.AsSpan(list8);
|
|
span5[0] = "개선 방안";
|
|
span5[1] = "실행 계획";
|
|
obj6.KeyPoints = list8;
|
|
list3.Add(obj6);
|
|
SectionPlan obj7 = new SectionPlan
|
|
{
|
|
Id = "sec-6",
|
|
Heading = "6. 결론",
|
|
Level = 1
|
|
};
|
|
num = 3;
|
|
List<string> list9 = new List<string>(num);
|
|
CollectionsMarshal.SetCount(list9, num);
|
|
Span<string> span6 = CollectionsMarshal.AsSpan(list9);
|
|
span6[0] = "요약";
|
|
span6[1] = "기대 효과";
|
|
span6[2] = "향후 과제";
|
|
obj7.KeyPoints = list9;
|
|
list3.Add(obj7);
|
|
result = list3;
|
|
break;
|
|
}
|
|
}
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static void DistributeWordCount(List<SectionPlan> sections, int totalWords)
|
|
{
|
|
if (sections.Count != 0)
|
|
{
|
|
double[] array = new double[sections.Count];
|
|
for (int i = 0; i < sections.Count; i++)
|
|
{
|
|
array[i] = ((i == 0 || i == sections.Count - 1) ? 0.7 : 1.2);
|
|
}
|
|
double num = array.Sum();
|
|
for (int j = 0; j < sections.Count; j++)
|
|
{
|
|
sections[j].TargetWords = Math.Max(100, (int)((double)totalWords * array[j] / num));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string SanitizeFileName(string name)
|
|
{
|
|
string text = ((name.Length > 60) ? name.Substring(0, 60) : name);
|
|
char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
|
|
foreach (char oldChar in invalidFileNameChars)
|
|
{
|
|
text = text.Replace(oldChar, '_');
|
|
}
|
|
return text.Trim().TrimEnd('.');
|
|
}
|
|
|
|
private static string GetDocTypeLabel(string docType)
|
|
{
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string result;
|
|
switch (docType)
|
|
{
|
|
case "proposal":
|
|
result = "제안서";
|
|
break;
|
|
case "analysis":
|
|
result = "분석 보고서";
|
|
break;
|
|
case "manual":
|
|
case "guide":
|
|
result = "매뉴얼/가이드";
|
|
break;
|
|
case "minutes":
|
|
result = "회의록";
|
|
break;
|
|
case "presentation":
|
|
result = "프레젠테이션";
|
|
break;
|
|
default:
|
|
result = "보고서";
|
|
break;
|
|
}
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static string Escape(string text)
|
|
{
|
|
return text.Replace("&", "&").Replace("<", "<").Replace(">", ">");
|
|
}
|
|
}
|