Add Tornado scene adapter boundary
This commit is contained in:
105
TornadoAce_CJOnStyle/Services/MockTornadoSceneAdapter.cs
Normal file
105
TornadoAce_CJOnStyle/Services/MockTornadoSceneAdapter.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using TornadoAce_CJOnStyle.Domain;
|
||||||
|
|
||||||
|
namespace TornadoAce_CJOnStyle.Services
|
||||||
|
{
|
||||||
|
public sealed class MockTornadoSceneAdapter : ITornadoSceneAdapter
|
||||||
|
{
|
||||||
|
private readonly AutomationWorkspace workspace;
|
||||||
|
|
||||||
|
public MockTornadoSceneAdapter(AutomationWorkspace workspace)
|
||||||
|
{
|
||||||
|
this.workspace = workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<SceneDataSnapshot> CreateOrUpdateSceneAsync(
|
||||||
|
CueSheetRecord cueSheet,
|
||||||
|
SceneTemplateDefinition template,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var visibleObjects = BuildVisibleTextObjects(cueSheet, template);
|
||||||
|
return Task.FromResult(BuildSnapshot(cueSheet, template, visibleObjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<SceneDataSnapshot> ExtractSceneDataAsync(string scenePath, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var cueSheet = FindCueSheet(scenePath) ?? workspace.CueSheets.First();
|
||||||
|
var visibleObjects = BuildVisibleTextObjects(cueSheet, workspace.ActiveTemplate);
|
||||||
|
|
||||||
|
if (cueSheet.CueSheetId.EndsWith("-002", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
visibleObjects["TXT_PRICE"] = "79,900원";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cueSheet.CueSheetId.EndsWith("-003", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
visibleObjects["TXT_PROMOTION"] = "앱 주문 추가 적립 ※";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(BuildSnapshot(cueSheet, workspace.ActiveTemplate, visibleObjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<TornadoAdapterCheck> GetAdapterChecks()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new TornadoAdapterCheck("SDK-01", "Tornado2 Scene 생성", "Mock", "CreateOrUpdateSceneAsync"),
|
||||||
|
new TornadoAdapterCheck("SDK-02", "Scene Data API 추출", "Mock", "ExtractSceneDataAsync"),
|
||||||
|
new TornadoAdapterCheck("SDK-03", "Tornado3 전환 경계", "준비", "ITornadoSceneAdapter 유지")
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private CueSheetRecord? FindCueSheet(string scenePath)
|
||||||
|
{
|
||||||
|
return workspace.CueSheets.FirstOrDefault(cueSheet => scenePath.Contains(cueSheet.BroadcastTime.ToString("HHmm"), StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SceneDataSnapshot BuildSnapshot(
|
||||||
|
CueSheetRecord cueSheet,
|
||||||
|
SceneTemplateDefinition template,
|
||||||
|
IReadOnlyDictionary<string, string> visibleObjects)
|
||||||
|
{
|
||||||
|
var sceneName = $"{template.TemplateId}_{cueSheet.BroadcastTime:HHmm}.tscn";
|
||||||
|
return new SceneDataSnapshot(sceneName, template.TemplateId, visibleObjects, [BuildImagePath(cueSheet)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> BuildVisibleTextObjects(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
||||||
|
{
|
||||||
|
return template.Mappings.ToDictionary(
|
||||||
|
mapping => mapping.SceneObjectName,
|
||||||
|
mapping => ReadCueSheetValue(cueSheet, mapping.CueSheetField),
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadCueSheetValue(CueSheetRecord cueSheet, string fieldName)
|
||||||
|
{
|
||||||
|
return fieldName switch
|
||||||
|
{
|
||||||
|
"programTitle" => cueSheet.ProgramTitle,
|
||||||
|
"productName" => cueSheet.ProductName,
|
||||||
|
"priceText" => cueSheet.PriceText,
|
||||||
|
"compositionText" => cueSheet.CompositionText,
|
||||||
|
"promotionText" => cueSheet.PromotionText,
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildImagePath(CueSheetRecord cueSheet)
|
||||||
|
{
|
||||||
|
var directoryName = new string(cueSheet.ProductName
|
||||||
|
.Select(character => char.IsLetterOrDigit(character) ? character : '_')
|
||||||
|
.ToArray()).Trim('_');
|
||||||
|
|
||||||
|
return $@"D:\CJOnStyle\Products\{directoryName}\main.png";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record TornadoAdapterCheck(
|
||||||
|
string CheckId,
|
||||||
|
string Name,
|
||||||
|
string Status,
|
||||||
|
string Evidence);
|
||||||
|
}
|
||||||
@@ -6,10 +6,12 @@ namespace TornadoAce_CJOnStyle.Services
|
|||||||
public sealed class PocAutomationEngine
|
public sealed class PocAutomationEngine
|
||||||
{
|
{
|
||||||
private readonly AutomationWorkspace workspace;
|
private readonly AutomationWorkspace workspace;
|
||||||
|
private readonly ITornadoSceneAdapter tornadoSceneAdapter;
|
||||||
|
|
||||||
public PocAutomationEngine(AutomationWorkspace workspace)
|
public PocAutomationEngine(AutomationWorkspace workspace, ITornadoSceneAdapter? tornadoSceneAdapter = null)
|
||||||
{
|
{
|
||||||
this.workspace = workspace;
|
this.workspace = workspace;
|
||||||
|
this.tornadoSceneAdapter = tornadoSceneAdapter ?? new MockTornadoSceneAdapter(workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CueSheetSelection SelectCueSheet(int index)
|
public CueSheetSelection SelectCueSheet(int index)
|
||||||
@@ -25,7 +27,20 @@ namespace TornadoAce_CJOnStyle.Services
|
|||||||
|
|
||||||
public SceneDataSnapshot GenerateScene(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
public SceneDataSnapshot GenerateScene(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
||||||
{
|
{
|
||||||
return BuildSnapshot(cueSheet, template, BuildVisibleTextObjects(cueSheet, template));
|
return tornadoSceneAdapter
|
||||||
|
.CreateOrUpdateSceneAsync(cueSheet, template, CancellationToken.None)
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<TornadoAdapterCheck> GetTornadoAdapterChecks()
|
||||||
|
{
|
||||||
|
return tornadoSceneAdapter is MockTornadoSceneAdapter mockAdapter
|
||||||
|
? mockAdapter.GetAdapterChecks()
|
||||||
|
:
|
||||||
|
[
|
||||||
|
new TornadoAdapterCheck("SDK-01", "Tornado Scene Adapter", "준비", tornadoSceneAdapter.GetType().Name)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<MappingValidationResult> ValidateMappingProfile(SceneTemplateDefinition template)
|
public IReadOnlyList<MappingValidationResult> ValidateMappingProfile(SceneTemplateDefinition template)
|
||||||
@@ -83,7 +98,16 @@ namespace TornadoAce_CJOnStyle.Services
|
|||||||
public PocInspectionSummary InspectWorkspace(SceneTemplateDefinition template)
|
public PocInspectionSummary InspectWorkspace(SceneTemplateDefinition template)
|
||||||
{
|
{
|
||||||
var results = workspace.CueSheets
|
var results = workspace.CueSheets
|
||||||
.Select(cueSheet => Inspect(cueSheet, GenerateExtractedScene(cueSheet, template), template))
|
.Select(cueSheet =>
|
||||||
|
{
|
||||||
|
var generatedScene = GenerateScene(cueSheet, template);
|
||||||
|
var extractedScene = tornadoSceneAdapter
|
||||||
|
.ExtractSceneDataAsync(generatedScene.SceneName, CancellationToken.None)
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
|
|
||||||
|
return Inspect(cueSheet, extractedScene, template);
|
||||||
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var reviewCount = results.Count(result => result.Severity is "High" or "Medium");
|
var reviewCount = results.Count(result => result.Severity is "High" or "Medium");
|
||||||
@@ -171,32 +195,6 @@ namespace TornadoAce_CJOnStyle.Services
|
|||||||
return new InspectionResult(cueSheet.CueSheetId, cueSheet.ProgramTitle, snapshot.SceneName, matchRate, severity, decision, fieldResults);
|
return new InspectionResult(cueSheet.CueSheetId, cueSheet.ProgramTitle, snapshot.SceneName, matchRate, severity, decision, fieldResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SceneDataSnapshot GenerateExtractedScene(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
|
||||||
{
|
|
||||||
var visibleObjects = BuildVisibleTextObjects(cueSheet, template);
|
|
||||||
|
|
||||||
if (cueSheet.CueSheetId.EndsWith("-002", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
visibleObjects["TXT_PRICE"] = "79,900원";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cueSheet.CueSheetId.EndsWith("-003", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
visibleObjects["TXT_PROMOTION"] = "앱 주문 추가 적립 ※";
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuildSnapshot(cueSheet, template, visibleObjects);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SceneDataSnapshot BuildSnapshot(
|
|
||||||
CueSheetRecord cueSheet,
|
|
||||||
SceneTemplateDefinition template,
|
|
||||||
IReadOnlyDictionary<string, string> visibleObjects)
|
|
||||||
{
|
|
||||||
var sceneName = $"{template.TemplateId}_{cueSheet.BroadcastTime:HHmm}.tscn";
|
|
||||||
return new SceneDataSnapshot(sceneName, template.TemplateId, visibleObjects, [BuildImagePath(cueSheet)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, string> BuildVisibleTextObjects(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
private static Dictionary<string, string> BuildVisibleTextObjects(CueSheetRecord cueSheet, SceneTemplateDefinition template)
|
||||||
{
|
{
|
||||||
return template.Mappings.ToDictionary(
|
return template.Mappings.ToDictionary(
|
||||||
@@ -218,15 +216,6 @@ namespace TornadoAce_CJOnStyle.Services
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string BuildImagePath(CueSheetRecord cueSheet)
|
|
||||||
{
|
|
||||||
var directoryName = new string(cueSheet.ProductName
|
|
||||||
.Select(character => char.IsLetterOrDigit(character) ? character : '_')
|
|
||||||
.ToArray()).Trim('_');
|
|
||||||
|
|
||||||
return $@"D:\CJOnStyle\Products\{directoryName}\main.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MappingValidationResult BuildValidationResult(
|
private static MappingValidationResult BuildValidationResult(
|
||||||
string checkId,
|
string checkId,
|
||||||
string title,
|
string title,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
|||||||
LoadFieldMappings();
|
LoadFieldMappings();
|
||||||
LoadMappingValidation();
|
LoadMappingValidation();
|
||||||
LoadEndpoints();
|
LoadEndpoints();
|
||||||
|
LoadTornadoAdapterChecks();
|
||||||
LoadRequirementCoverage();
|
LoadRequirementCoverage();
|
||||||
LoadScheduleMatches();
|
LoadScheduleMatches();
|
||||||
LoadInspectionQueue(initialInspectionSummary.Results);
|
LoadInspectionQueue(initialInspectionSummary.Results);
|
||||||
@@ -132,6 +133,8 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
|||||||
|
|
||||||
public ObservableCollection<IntegrationEndpointViewModel> Endpoints { get; } = [];
|
public ObservableCollection<IntegrationEndpointViewModel> Endpoints { get; } = [];
|
||||||
|
|
||||||
|
public ObservableCollection<TornadoAdapterCheckViewModel> TornadoAdapterChecks { get; } = [];
|
||||||
|
|
||||||
public ObservableCollection<PocRequirementViewModel> RequirementCoverage { get; } = [];
|
public ObservableCollection<PocRequirementViewModel> RequirementCoverage { get; } = [];
|
||||||
|
|
||||||
public ObservableCollection<ScheduleMatchViewModel> ScheduleMatches { get; } = [];
|
public ObservableCollection<ScheduleMatchViewModel> ScheduleMatches { get; } = [];
|
||||||
@@ -233,15 +236,15 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
|||||||
StatusCards.Add(new StatusCardViewModel("큐시트 API", "12", "수신 대기", Symbol.Sync, Brush(0xFF45D6D1)));
|
StatusCards.Add(new StatusCardViewModel("큐시트 API", "12", "수신 대기", Symbol.Sync, Brush(0xFF45D6D1)));
|
||||||
StatusCards.Add(new StatusCardViewModel("Scene 매핑", "5", "템플릿 정의", Symbol.Map, Brush(0xFFB48CFF)));
|
StatusCards.Add(new StatusCardViewModel("Scene 매핑", "5", "템플릿 정의", Symbol.Map, Brush(0xFFB48CFF)));
|
||||||
StatusCards.Add(new StatusCardViewModel("자동 검수", "98.7%", "목표 99%+", Symbol.Accept, Brush(0xFFFFB547)));
|
StatusCards.Add(new StatusCardViewModel("자동 검수", "98.7%", "목표 99%+", Symbol.Accept, Brush(0xFFFFB547)));
|
||||||
StatusCards.Add(new StatusCardViewModel("Tornado", "Mock", "SDK 어댑터 자리", Symbol.Repair, Brush(0xFF37D67A)));
|
StatusCards.Add(new StatusCardViewModel("Tornado", "Adapter", "Mock SDK 경계", Symbol.Repair, Brush(0xFF37D67A)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadPipelineSteps()
|
private void LoadPipelineSteps()
|
||||||
{
|
{
|
||||||
PipelineSteps.Add(new PipelineStepViewModel("01", "큐시트/ERP 데이터 수신", "AI ON Studio / CJ OnStyle ERP", "PoC", 55, Brush(0xFF45D6D1)));
|
PipelineSteps.Add(new PipelineStepViewModel("01", "큐시트/ERP 데이터 수신", "AI ON Studio / CJ OnStyle ERP", "PoC", 55, Brush(0xFF45D6D1)));
|
||||||
PipelineSteps.Add(new PipelineStepViewModel("02", "Data Field Mapping", "큐시트 필드 -> Tornado Scene 객체", "초안", 45, Brush(0xFFB48CFF)));
|
PipelineSteps.Add(new PipelineStepViewModel("02", "Data Field Mapping", "큐시트 필드 -> Tornado Scene 객체", "초안", 45, Brush(0xFFB48CFF)));
|
||||||
PipelineSteps.Add(new PipelineStepViewModel("03", "Scene 생성/갱신", "Tornado2 우선, Tornado3 어댑터 준비", "대기", 25, Brush(0xFF37D67A)));
|
PipelineSteps.Add(new PipelineStepViewModel("03", "Scene 생성/갱신", "Tornado2 우선, Tornado3 adapter ready", "PoC", 55, Brush(0xFF37D67A)));
|
||||||
PipelineSteps.Add(new PipelineStepViewModel("04", "Scene Data API 추출", "Text/Image visible object snapshot", "초안", 30, Brush(0xFFFFB547)));
|
PipelineSteps.Add(new PipelineStepViewModel("04", "Scene Data API 추출", "Text/Image visible object snapshot", "PoC", 50, Brush(0xFFFFB547)));
|
||||||
PipelineSteps.Add(new PipelineStepViewModel("05", "자동 검수 피드백", "Text Diffing + LLM 중요도 판정", "초안", 40, Brush(0xFFFF5B61)));
|
PipelineSteps.Add(new PipelineStepViewModel("05", "자동 검수 피드백", "Text Diffing + LLM 중요도 판정", "초안", 40, Brush(0xFFFF5B61)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,16 +275,31 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
|||||||
{
|
{
|
||||||
Endpoints.Add(new IntegrationEndpointViewModel("큐시트 플랫폼", "GET /api/cuesheets/{broadcastDate}", "AI ON Studio", "Mock", Brush(0xFF45D6D1)));
|
Endpoints.Add(new IntegrationEndpointViewModel("큐시트 플랫폼", "GET /api/cuesheets/{broadcastDate}", "AI ON Studio", "Mock", Brush(0xFF45D6D1)));
|
||||||
Endpoints.Add(new IntegrationEndpointViewModel("ERP 편성", "GET /api/schedules/{programCode}", "CJ OnStyle ERP", "Mock", Brush(0xFF37D67A)));
|
Endpoints.Add(new IntegrationEndpointViewModel("ERP 편성", "GET /api/schedules/{programCode}", "CJ OnStyle ERP", "Mock", Brush(0xFF37D67A)));
|
||||||
Endpoints.Add(new IntegrationEndpointViewModel("Tornado Scene API", "POST /api/scenes/extract", "Tornado Adapter", "설계", Brush(0xFF37D67A)));
|
Endpoints.Add(new IntegrationEndpointViewModel("Tornado Scene API", "POST /api/scenes/extract", "Tornado Adapter", "Mock", Brush(0xFF37D67A)));
|
||||||
Endpoints.Add(new IntegrationEndpointViewModel("LLM 검수", "POST /api/inspection/llm", "Internal LLM", "정책 확인", Brush(0xFFB48CFF)));
|
Endpoints.Add(new IntegrationEndpointViewModel("LLM 검수", "POST /api/inspection/llm", "Internal LLM", "정책 확인", Brush(0xFFB48CFF)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadTornadoAdapterChecks()
|
||||||
|
{
|
||||||
|
TornadoAdapterChecks.Clear();
|
||||||
|
|
||||||
|
foreach (var check in automationEngine.GetTornadoAdapterChecks())
|
||||||
|
{
|
||||||
|
TornadoAdapterChecks.Add(new TornadoAdapterCheckViewModel(
|
||||||
|
check.CheckId,
|
||||||
|
check.Name,
|
||||||
|
check.Status,
|
||||||
|
check.Evidence,
|
||||||
|
check.Status == "준비" ? Brush(0xFFFFB547) : Brush(0xFF37D67A)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadRequirementCoverage()
|
private void LoadRequirementCoverage()
|
||||||
{
|
{
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-01", "큐시트 API 연동", "PoC", "JSON Mock 수신", Brush(0xFF45D6D1)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-01", "큐시트 API 연동", "PoC", "JSON Mock 수신", Brush(0xFF45D6D1)));
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-02", "ERP 편성 연동", "PoC", "편성 JSON 매칭", Brush(0xFF37D67A)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-02", "ERP 편성 연동", "PoC", "편성 JSON 매칭", Brush(0xFF37D67A)));
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-03", "Data Field Mapping", "PoC", "Scene 스냅샷 생성", Brush(0xFF37D67A)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-03", "Data Field Mapping", "PoC", "Scene 스냅샷 생성", Brush(0xFF37D67A)));
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-04", "Tornado Scene API", "PoC", "Text/Image 추출 샘플", Brush(0xFF37D67A)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-04", "Tornado Scene API", "PoC", "Mock adapter 추출", Brush(0xFF37D67A)));
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-05", "관리자 매핑 기능", "PoC", "프로파일 검증", Brush(0xFF37D67A)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-05", "관리자 매핑 기능", "PoC", "프로파일 검증", Brush(0xFF37D67A)));
|
||||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-06", "1·2단계 자동 검수", "PoC", "필드 상세 Diff + LLM 후보", Brush(0xFF45D6D1)));
|
RequirementCoverage.Add(new PocRequirementViewModel("RFP-06", "1·2단계 자동 검수", "PoC", "필드 상세 Diff + LLM 후보", Brush(0xFF45D6D1)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,13 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
|||||||
public string OwnerAndStatus => $"{Owner} / {Status}";
|
public string OwnerAndStatus => $"{Owner} / {Status}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed record TornadoAdapterCheckViewModel(
|
||||||
|
string CheckId,
|
||||||
|
string Name,
|
||||||
|
string Status,
|
||||||
|
string Evidence,
|
||||||
|
SolidColorBrush StatusBrush);
|
||||||
|
|
||||||
public sealed record PocRequirementViewModel(
|
public sealed record PocRequirementViewModel(
|
||||||
string RequirementId,
|
string RequirementId,
|
||||||
string Title,
|
string Title,
|
||||||
|
|||||||
@@ -436,6 +436,54 @@
|
|||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Height="1"
|
||||||
|
Background="{StaticResource PanelStrokeBrush}" />
|
||||||
|
|
||||||
|
<TextBlock Style="{StaticResource SectionTitleTextStyle}" Text="Tornado Adapter" />
|
||||||
|
<ItemsControl ItemsSource="{x:Bind ViewModel.TornadoAdapterChecks, Mode=OneWay}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TornadoAdapterCheckViewModel">
|
||||||
|
<Grid
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
ColumnSpacing="10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="58" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
FontFamily="Cascadia Mono"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{StaticResource TextMutedBrush}"
|
||||||
|
Text="{x:Bind CheckId}" />
|
||||||
|
<StackPanel Grid.Column="1" Spacing="2">
|
||||||
|
<TextBlock
|
||||||
|
FontFamily="Bahnschrift SemiBold"
|
||||||
|
Foreground="{StaticResource TextPrimaryBrush}"
|
||||||
|
Text="{x:Bind Name}"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
<TextBlock
|
||||||
|
Style="{StaticResource LabelTextStyle}"
|
||||||
|
Text="{x:Bind Evidence}"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
</StackPanel>
|
||||||
|
<Border
|
||||||
|
Grid.Column="2"
|
||||||
|
Padding="8,3"
|
||||||
|
Background="{x:Bind StatusBrush}"
|
||||||
|
CornerRadius="8">
|
||||||
|
<TextBlock
|
||||||
|
FontFamily="Bahnschrift SemiBold"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="#071013"
|
||||||
|
Text="{x:Bind Status}" />
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Height="1"
|
Height="1"
|
||||||
Background="{StaticResource PanelStrokeBrush}" />
|
Background="{StaticResource PanelStrokeBrush}" />
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
- `Domain`: 큐시트, Scene 템플릿, Scene 데이터 스냅샷, 검수 결과 모델.
|
- `Domain`: 큐시트, Scene 템플릿, Scene 데이터 스냅샷, 검수 결과 모델.
|
||||||
- `Data`: 큐시트, ERP 편성, Scene 템플릿, Scene 추출값을 담은 JSON 기반 PoC 샘플.
|
- `Data`: 큐시트, ERP 편성, Scene 템플릿, Scene 추출값을 담은 JSON 기반 PoC 샘플.
|
||||||
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스, JSON 로더, 목 워크스페이스.
|
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스, JSON 로더, 목 워크스페이스, Mock Tornado adapter.
|
||||||
- `ViewModels`: 운영 콘솔에 표시할 상태 카드, 파이프라인, 매핑표, 검수 큐.
|
- `ViewModels`: 운영 콘솔에 표시할 상태 카드, 파이프라인, 매핑표, 검수 큐.
|
||||||
- `Views`: WinUI 3 기반 첫 화면. 예제 프로젝트와 같은 데스크톱 앱 방향으로 유지.
|
- `Views`: WinUI 3 기반 첫 화면. 예제 프로젝트와 같은 데스크톱 앱 방향으로 유지.
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
| RFP-01 | 신규 큐시트 플랫폼 API 연동 | JSON Mock 데이터 수신 흐름 구현 | `Data/PocWorkspace.json`, `AutomationWorkspace.CueSheets`, `RefreshCueSheetCommand` |
|
| RFP-01 | 신규 큐시트 플랫폼 API 연동 | JSON Mock 데이터 수신 흐름 구현 | `Data/PocWorkspace.json`, `AutomationWorkspace.CueSheets`, `RefreshCueSheetCommand` |
|
||||||
| RFP-02 | ERP 편성데이터 연동 | JSON Mock 편성 데이터 매칭 구현 | `Data/PocWorkspace.json`, `ErpScheduleRecord`, `ScheduleMatches` |
|
| RFP-02 | ERP 편성데이터 연동 | JSON Mock 편성 데이터 매칭 구현 | `Data/PocWorkspace.json`, `ErpScheduleRecord`, `ScheduleMatches` |
|
||||||
| RFP-03 | CG 포맷 제작 자동화, Data Field Mapping | 큐시트 필드와 Scene 객체 매핑 구현 | `SceneTemplateDefinition`, `PocAutomationEngine.GenerateScene` |
|
| RFP-03 | CG 포맷 제작 자동화, Data Field Mapping | 큐시트 필드와 Scene 객체 매핑 구현 | `SceneTemplateDefinition`, `PocAutomationEngine.GenerateScene` |
|
||||||
| RFP-04 | Tornado Scene API | Scene visible Text/Image 스냅샷 샘플 구현 | `SceneDataSnapshot.ToPreviewJson` |
|
| RFP-04 | Tornado Scene API | Mock Tornado adapter 기반 Scene 생성/추출 구현 | `ITornadoSceneAdapter`, `MockTornadoSceneAdapter`, `SceneDataSnapshot.ToPreviewJson` |
|
||||||
| RFP-05 | 큐시트 데이터와 Tornado Scene 연동 관리자 기능 | JSON 매핑 프로파일과 검증 UI 구현 | `FieldMappings`, `MappingValidations`, `ValidateMappingProfile` |
|
| RFP-05 | 큐시트 데이터와 Tornado Scene 연동 관리자 기능 | JSON 매핑 프로파일과 검증 UI 구현 | `FieldMappings`, `MappingValidations`, `ValidateMappingProfile` |
|
||||||
| RFP-06 | 자동 검수 1단계 Text Diffing | 필드별 기대값/실제값/일치율 비교 구현 | `PocAutomationEngine.InspectWorkspace`, `InspectionFieldResult` |
|
| RFP-06 | 자동 검수 1단계 Text Diffing | 필드별 기대값/실제값/일치율 비교 구현 | `PocAutomationEngine.InspectWorkspace`, `InspectionFieldResult` |
|
||||||
| RFP-07 | 자동 검수 2단계 LLM 중요도 피드백 | LLM 요청 후보 payload와 제작자 상세 UI 구현 | `LlmReviewRequest`, `BuildLlmReviewRequests`, `LlmReviewRequests` |
|
| RFP-07 | 자동 검수 2단계 LLM 중요도 피드백 | LLM 요청 후보 payload와 제작자 상세 UI 구현 | `LlmReviewRequest`, `BuildLlmReviewRequests`, `LlmReviewRequests` |
|
||||||
@@ -34,6 +34,6 @@
|
|||||||
|
|
||||||
- 실제 큐시트/ERP API 응답 DTO와 현재 JSON seed 스키마를 대조한다.
|
- 실제 큐시트/ERP API 응답 DTO와 현재 JSON seed 스키마를 대조한다.
|
||||||
- 관리자용 매핑 프로파일 편집/저장 권한 정책을 정한다.
|
- 관리자용 매핑 프로파일 편집/저장 권한 정책을 정한다.
|
||||||
- Tornado2/Tornado3 어댑터를 동일 인터페이스로 유지하고, 버전별 구현체를 분리한다.
|
- 실제 Tornado2 SDK 구현체와 Tornado3 SDK 구현체의 메서드 차이를 `ITornadoSceneAdapter`에 맞춰 정리한다.
|
||||||
- Scene 내부 비노출 객체를 구분할 메타데이터 규칙을 정의한다.
|
- Scene 내부 비노출 객체를 구분할 메타데이터 규칙을 정의한다.
|
||||||
- LLM 응답 스키마와 감사 로그 보관 정책을 실제 사내 정책에 맞춘다.
|
- LLM 응답 스키마와 감사 로그 보관 정책을 실제 사내 정책에 맞춘다.
|
||||||
|
|||||||
Reference in New Issue
Block a user