Persist PoC run audit logs
This commit is contained in:
66
TornadoAce_CJOnStyle/Services/PocRunLogWriter.cs
Normal file
66
TornadoAce_CJOnStyle/Services/PocRunLogWriter.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace TornadoAce_CJOnStyle.Services
|
||||
{
|
||||
public sealed class PocRunLogWriter
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public string Write(PocRunResult result)
|
||||
{
|
||||
var logDirectory = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"TornadoAce_CJOnStyle",
|
||||
"Logs");
|
||||
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
|
||||
var fileName = $"{DateTime.Now:yyyyMMdd-HHmmss}-{SanitizeFileName(result.Selection.Record.CueSheetId)}.json";
|
||||
var logPath = Path.Combine(logDirectory, fileName);
|
||||
var entry = PocRunLogEntry.From(result);
|
||||
|
||||
File.WriteAllText(logPath, JsonSerializer.Serialize(entry, JsonOptions));
|
||||
return logPath;
|
||||
}
|
||||
|
||||
private static string SanitizeFileName(string value)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
var chars = value.Select(character => invalidChars.Contains(character) ? '_' : character).ToArray();
|
||||
return new string(chars);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record PocRunLogEntry(
|
||||
DateTime CreatedAt,
|
||||
string CueSheetId,
|
||||
string ProgramTitle,
|
||||
string? ErpProgramCode,
|
||||
string SceneName,
|
||||
double AverageMatchRate,
|
||||
int ReviewCount,
|
||||
int LlmRequestCount,
|
||||
IReadOnlyList<string> MappingChecks,
|
||||
IReadOnlyList<string> AdapterChecks,
|
||||
IReadOnlyList<string> LlmAuditSummaries)
|
||||
{
|
||||
public static PocRunLogEntry From(PocRunResult result)
|
||||
{
|
||||
return new PocRunLogEntry(
|
||||
DateTime.Now,
|
||||
result.Selection.Record.CueSheetId,
|
||||
result.Selection.Record.ProgramTitle,
|
||||
result.Schedule?.ProgramCode,
|
||||
result.GeneratedScene.SceneName,
|
||||
result.InspectionSummary.AverageMatchRate,
|
||||
result.InspectionSummary.ReviewCount,
|
||||
result.LlmReviewRequests.Count,
|
||||
result.MappingValidations.Select(check => $"{check.CheckId}:{check.Status}:{check.Detail}").ToArray(),
|
||||
result.AdapterChecks.Select(check => $"{check.CheckId}:{check.Status}:{check.Evidence}").ToArray(),
|
||||
result.LlmReviewRequests.Select(request => request.AuditSummary).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
{
|
||||
private readonly AutomationWorkspace workspace;
|
||||
private readonly PocAutomationEngine automationEngine;
|
||||
private readonly PocRunLogWriter pocRunLogWriter = new();
|
||||
private int selectedCueSheetIndex;
|
||||
private CueSheetRecord activeCueSheet = null!;
|
||||
private ErpScheduleRecord? activeSchedule;
|
||||
@@ -40,6 +41,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
LaunchMessage = "TornadoAce";
|
||||
LlmPolicyText = "사내 LLM 우선, 외부 서비스는 정책 승인 후";
|
||||
LlmPolicyDetail = "1차 Text Diffing 실패 건만 2차 LLM 판정으로 이동하고, 가격·구성·방송시간 변경은 높은 중요도로 표시합니다.";
|
||||
PocRunLogText = "PoC 로그 대기";
|
||||
|
||||
LoadStatusCards();
|
||||
LoadPipelineSteps();
|
||||
@@ -63,6 +65,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
private string sceneSnapshotText = string.Empty;
|
||||
private string llmPolicyText = string.Empty;
|
||||
private string llmPolicyDetail = string.Empty;
|
||||
private string pocRunLogText = string.Empty;
|
||||
private string loginOperatorName = string.Empty;
|
||||
private string launchMessage = string.Empty;
|
||||
private Visibility loginScreenVisibility = Visibility.Visible;
|
||||
@@ -123,6 +126,12 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
set => SetProperty(ref llmPolicyDetail, value);
|
||||
}
|
||||
|
||||
public string PocRunLogText
|
||||
{
|
||||
get => pocRunLogText;
|
||||
set => SetProperty(ref pocRunLogText, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<StatusCardViewModel> StatusCards { get; } = [];
|
||||
|
||||
public ObservableCollection<PipelineStepViewModel> PipelineSteps { get; } = [];
|
||||
@@ -235,6 +244,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
private void RunPoc()
|
||||
{
|
||||
var result = automationEngine.RunFullPoc(selectedCueSheetIndex, workspace.ActiveTemplate);
|
||||
var logPath = pocRunLogWriter.Write(result);
|
||||
activeCueSheet = result.Selection.Record;
|
||||
activeSchedule = result.Schedule;
|
||||
activeScene = result.GeneratedScene;
|
||||
@@ -243,6 +253,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
ActiveTemplateName = workspace.ActiveTemplate.TemplateName;
|
||||
InspectionSummary = FormatInspectionSummary(result.InspectionSummary);
|
||||
OperatorMessage = FormatPocRunSummary(result);
|
||||
PocRunLogText = $"로그 저장: {Path.GetFileName(logPath)}";
|
||||
|
||||
StatusCards[0].Metric = result.Selection.TotalCount.ToString();
|
||||
StatusCards[0].Detail = $"ERP {FormatScheduleStatus(result.Schedule)}";
|
||||
|
||||
@@ -116,9 +116,10 @@
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10"
|
||||
HorizontalAlignment="Right"
|
||||
Spacing="8"
|
||||
VerticalAlignment="Top">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.RunPocCommand}"
|
||||
Style="{StaticResource PrimaryActionButtonStyle}">
|
||||
@@ -152,6 +153,11 @@
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource LabelTextStyle}"
|
||||
Text="{x:Bind ViewModel.PocRunLogText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<ItemsControl
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
- `Domain`: 큐시트, Scene 템플릿, Scene 데이터 스냅샷, 검수 결과 모델.
|
||||
- `Data`: 큐시트, ERP 편성, Scene 템플릿, Scene 추출값을 담은 JSON 기반 PoC 샘플.
|
||||
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스, JSON 로더, 목 워크스페이스, Mock Tornado adapter.
|
||||
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스, JSON 로더, 목 워크스페이스, Mock Tornado adapter, PoC 실행 로그 저장.
|
||||
- `ViewModels`: 운영 콘솔에 표시할 상태 카드, 파이프라인, 매핑표, 검수 큐.
|
||||
- `Views`: WinUI 3 기반 첫 화면. 예제 프로젝트와 같은 데스크톱 앱 방향으로 유지.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
1. Windows 데스크톱 앱으로 실행 가능한 WinUI 3 빌드가 유지된다.
|
||||
2. CJ OnStyle/TornadoAce 정체성이 드러나는 로그인 도입 화면과 앱 아이콘이 적용된다.
|
||||
3. `PoC 실행`으로 큐시트 선택, ERP 매칭, Scene 스냅샷 생성, 자동 검수, LLM 후보 생성이 한 번에 갱신된다.
|
||||
3. `PoC 실행`으로 큐시트 선택, ERP 매칭, Scene 스냅샷 생성, 자동 검수, LLM 후보 생성, 실행 로그 저장이 한 번에 갱신된다.
|
||||
4. RFP 구축 범위가 화면 또는 문서에서 추적 가능해야 한다.
|
||||
5. 추후 실제 큐시트 API, ERP API, Tornado SDK, LLM 서비스로 교체할 인터페이스 경계가 유지된다.
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
- 실제 Tornado2 SDK 구현체와 Tornado3 SDK 구현체의 메서드 차이를 `ITornadoSceneAdapter`에 맞춰 정리한다.
|
||||
- Scene 내부 비노출 객체를 구분할 메타데이터 규칙을 정의한다.
|
||||
- LLM 응답 스키마와 감사 로그 보관 정책을 실제 사내 정책에 맞춘다.
|
||||
- PoC 실행 결과를 파일 또는 운영 로그로 저장하는 정책을 정한다.
|
||||
- PoC 실행 로그의 보관 기간, 열람 권한, 운영 로그 연동 방식을 정한다.
|
||||
|
||||
Reference in New Issue
Block a user