Load PoC workspace from JSON
This commit is contained in:
108
TornadoAce_CJOnStyle/Data/PocWorkspace.json
Normal file
108
TornadoAce_CJOnStyle/Data/PocWorkspace.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"cueSheets": [
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-001",
|
||||
"broadcastTime": "2026-08-17T09:00:00",
|
||||
"programTitle": "최화정쇼",
|
||||
"productName": "비비안 컴포트 패키지",
|
||||
"priceText": "79,900원",
|
||||
"compositionText": "브라 4종 + 팬티 4종",
|
||||
"promotionText": "ARS 10% 할인"
|
||||
},
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-002",
|
||||
"broadcastTime": "2026-08-17T11:00:00",
|
||||
"programTitle": "동가게",
|
||||
"productName": "프리미엄 한우 세트",
|
||||
"priceText": "69,900원",
|
||||
"compositionText": "1등급 등심 1.2kg",
|
||||
"promotionText": "무이자 5개월"
|
||||
},
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-003",
|
||||
"broadcastTime": "2026-08-17T14:00:00",
|
||||
"programTitle": "스타일 라이브",
|
||||
"productName": "썸머 린넨 셋업",
|
||||
"priceText": "59,900원",
|
||||
"compositionText": "자켓 + 팬츠",
|
||||
"promotionText": "앱 주문 추가 적립"
|
||||
}
|
||||
],
|
||||
"activeTemplate": {
|
||||
"templateId": "CJ_PRICE_LOWER_01",
|
||||
"templateName": "가격형 하단 자막 / Tornado Scene",
|
||||
"tornadoVersion": "Tornado2 primary, Tornado3 ready",
|
||||
"mappings": [
|
||||
{
|
||||
"cueSheetField": "programTitle",
|
||||
"sceneObjectName": "TXT_PROGRAM",
|
||||
"attribute": "Text",
|
||||
"rule": "trim"
|
||||
},
|
||||
{
|
||||
"cueSheetField": "productName",
|
||||
"sceneObjectName": "TXT_PRODUCT",
|
||||
"attribute": "Text",
|
||||
"rule": "normalize-space"
|
||||
},
|
||||
{
|
||||
"cueSheetField": "priceText",
|
||||
"sceneObjectName": "TXT_PRICE",
|
||||
"attribute": "Text",
|
||||
"rule": "currency-text"
|
||||
},
|
||||
{
|
||||
"cueSheetField": "compositionText",
|
||||
"sceneObjectName": "TXT_COMPOSITION",
|
||||
"attribute": "Text",
|
||||
"rule": "line-break-safe"
|
||||
},
|
||||
{
|
||||
"cueSheetField": "promotionText",
|
||||
"sceneObjectName": "TXT_PROMOTION",
|
||||
"attribute": "Text",
|
||||
"rule": "special-char-exception"
|
||||
}
|
||||
]
|
||||
},
|
||||
"activeScene": {
|
||||
"sceneName": "CJ_PRICE_LOWER_01_0900.tscn",
|
||||
"templateId": "CJ_PRICE_LOWER_01",
|
||||
"visibleTextObjects": {
|
||||
"TXT_PROGRAM": "최화정쇼",
|
||||
"TXT_PRODUCT": "비비안 컴포트 패키지",
|
||||
"TXT_PRICE": "79,900원",
|
||||
"TXT_COMPOSITION": "브라 4종 + 팬티 4종",
|
||||
"TXT_PROMOTION": "ARS 10% 할인"
|
||||
},
|
||||
"imagePaths": [
|
||||
"D:\\CJOnStyle\\Products\\VIVIEN\\main.png"
|
||||
]
|
||||
},
|
||||
"inspectionResults": [
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-001",
|
||||
"programTitle": "최화정쇼",
|
||||
"sceneName": "CJ_PRICE_LOWER_01_0900.tscn",
|
||||
"matchRate": 100,
|
||||
"severity": "Low",
|
||||
"decision": "1차 통과"
|
||||
},
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-002",
|
||||
"programTitle": "동가게",
|
||||
"sceneName": "CJ_PRICE_LOWER_01_1100.tscn",
|
||||
"matchRate": 96.4,
|
||||
"severity": "High",
|
||||
"decision": "가격 불일치 확인"
|
||||
},
|
||||
{
|
||||
"cueSheetId": "CJ-20260817-003",
|
||||
"programTitle": "스타일 라이브",
|
||||
"sceneName": "CJ_PRICE_LOWER_01_1400.tscn",
|
||||
"matchRate": 98.1,
|
||||
"severity": "Medium",
|
||||
"decision": "특수문자 예외 후보"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Text.Json;
|
||||
using TornadoAce_CJOnStyle.Domain;
|
||||
|
||||
namespace TornadoAce_CJOnStyle.Services
|
||||
@@ -25,12 +26,50 @@ namespace TornadoAce_CJOnStyle.Services
|
||||
public IReadOnlyList<InspectionResult> InspectionResults { get; }
|
||||
|
||||
public static AutomationWorkspace CreateDemo()
|
||||
{
|
||||
return TryCreateFromSeedFile() ?? CreateEmbeddedDemo();
|
||||
}
|
||||
|
||||
private static AutomationWorkspace? TryCreateFromSeedFile()
|
||||
{
|
||||
var seedPath = Path.Combine(AppContext.BaseDirectory, "Data", "PocWorkspace.json");
|
||||
if (!File.Exists(seedPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(seedPath);
|
||||
var seed = JsonSerializer.Deserialize<WorkspaceSeed>(
|
||||
json,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (seed?.CueSheets is not { Count: > 0 } cueSheets
|
||||
|| seed.ActiveTemplate is null
|
||||
|| seed.ActiveScene is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var template = seed.ActiveTemplate.ToDomain();
|
||||
var scene = seed.ActiveScene.ToDomain();
|
||||
var inspections = seed.InspectionResults
|
||||
.Select(inspection => inspection.ToDomain())
|
||||
.ToArray();
|
||||
|
||||
return new AutomationWorkspace(
|
||||
cueSheets.Select(cueSheet => cueSheet.ToDomain()).ToArray(),
|
||||
template,
|
||||
scene,
|
||||
inspections);
|
||||
}
|
||||
|
||||
private static AutomationWorkspace CreateEmbeddedDemo()
|
||||
{
|
||||
var cueSheets = new[]
|
||||
{
|
||||
new CueSheetRecord("CJ-20260817-001", DateTime.Today.AddHours(9), "최화정쇼", "비비안 컴포트 패키지", "79,900원", "브라 4종 + 팬티 4종", "ARS 10% 할인"),
|
||||
new CueSheetRecord("CJ-20260817-002", DateTime.Today.AddHours(11), "동가게", "프리미엄 한우 세트", "69,900원", "1등급 등심 1.2kg", "무이자 5개월"),
|
||||
new CueSheetRecord("CJ-20260817-003", DateTime.Today.AddHours(14), "스타일 라이브", "썸머 린넨 셋업", "59,900원", "자켓 + 팬츠", "앱 주문 추가 적립")
|
||||
new CueSheetRecord("CJ-20260817-001", new DateTime(2026, 8, 17, 9, 0, 0), "최화정쇼", "비비안 컴포트 패키지", "79,900원", "브라 4종 + 팬티 4종", "ARS 10% 할인"),
|
||||
new CueSheetRecord("CJ-20260817-002", new DateTime(2026, 8, 17, 11, 0, 0), "동가게", "프리미엄 한우 세트", "69,900원", "1등급 등심 1.2kg", "무이자 5개월"),
|
||||
new CueSheetRecord("CJ-20260817-003", new DateTime(2026, 8, 17, 14, 0, 0), "스타일 라이브", "썸머 린넨 셋업", "59,900원", "자켓 + 팬츠", "앱 주문 추가 적립")
|
||||
};
|
||||
|
||||
var mappings = new[]
|
||||
@@ -66,5 +105,80 @@ namespace TornadoAce_CJOnStyle.Services
|
||||
|
||||
return new AutomationWorkspace(cueSheets, template, scene, inspections);
|
||||
}
|
||||
|
||||
private sealed record WorkspaceSeed(
|
||||
List<CueSheetSeed> CueSheets,
|
||||
SceneTemplateSeed ActiveTemplate,
|
||||
SceneDataSeed ActiveScene,
|
||||
List<InspectionSeed> InspectionResults);
|
||||
|
||||
private sealed record CueSheetSeed(
|
||||
string CueSheetId,
|
||||
DateTime BroadcastTime,
|
||||
string ProgramTitle,
|
||||
string ProductName,
|
||||
string PriceText,
|
||||
string CompositionText,
|
||||
string PromotionText)
|
||||
{
|
||||
public CueSheetRecord ToDomain()
|
||||
{
|
||||
return new CueSheetRecord(CueSheetId, BroadcastTime, ProgramTitle, ProductName, PriceText, CompositionText, PromotionText);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record SceneTemplateSeed(
|
||||
string TemplateId,
|
||||
string TemplateName,
|
||||
string TornadoVersion,
|
||||
List<FieldMappingSeed> Mappings)
|
||||
{
|
||||
public SceneTemplateDefinition ToDomain()
|
||||
{
|
||||
return new SceneTemplateDefinition(
|
||||
TemplateId,
|
||||
TemplateName,
|
||||
TornadoVersion,
|
||||
Mappings.Select(mapping => mapping.ToDomain()).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record FieldMappingSeed(
|
||||
string CueSheetField,
|
||||
string SceneObjectName,
|
||||
string Attribute,
|
||||
string Rule)
|
||||
{
|
||||
public FieldMappingDefinition ToDomain()
|
||||
{
|
||||
return new FieldMappingDefinition(CueSheetField, SceneObjectName, Attribute, Rule);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record SceneDataSeed(
|
||||
string SceneName,
|
||||
string TemplateId,
|
||||
Dictionary<string, string> VisibleTextObjects,
|
||||
List<string> ImagePaths)
|
||||
{
|
||||
public SceneDataSnapshot ToDomain()
|
||||
{
|
||||
return new SceneDataSnapshot(SceneName, TemplateId, VisibleTextObjects, ImagePaths);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record InspectionSeed(
|
||||
string CueSheetId,
|
||||
string ProgramTitle,
|
||||
string SceneName,
|
||||
double MatchRate,
|
||||
string Severity,
|
||||
string Decision)
|
||||
{
|
||||
public InspectionResult ToDomain()
|
||||
{
|
||||
return new InspectionResult(CueSheetId, ProgramTitle, SceneName, MatchRate, Severity, Decision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
<Content Include="Data\PocWorkspace.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace TornadoAce_CJOnStyle.ViewModels
|
||||
|
||||
private void LoadRequirementCoverage()
|
||||
{
|
||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-01", "큐시트 API 연동", "PoC", "샘플 큐시트 선택", Brush(0xFF45D6D1)));
|
||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-01", "큐시트 API 연동", "PoC", "JSON Mock 수신", Brush(0xFF45D6D1)));
|
||||
RequirementCoverage.Add(new PocRequirementViewModel("RFP-02", "ERP 편성 연동", "대기", "엔드포인트 자리", Brush(0xFFFFB547)));
|
||||
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)));
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
## 현재 초기 빌드 범위
|
||||
|
||||
- `Domain`: 큐시트, Scene 템플릿, Scene 데이터 스냅샷, 검수 결과 모델.
|
||||
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스와 목 워크스페이스.
|
||||
- `Data`: 큐시트, Scene 템플릿, Scene 추출값을 담은 JSON 기반 PoC 샘플.
|
||||
- `Services`: 실제 API/Tornado SDK 연결을 받을 인터페이스, JSON 로더, 목 워크스페이스.
|
||||
- `ViewModels`: 운영 콘솔에 표시할 상태 카드, 파이프라인, 매핑표, 검수 큐.
|
||||
- `Views`: WinUI 3 기반 첫 화면. 예제 프로젝트와 같은 데스크톱 앱 방향으로 유지.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
| ID | RFP 요구사항 | 초기 PoC 반영 상태 | 현재 구현 근거 |
|
||||
| --- | --- | --- | --- |
|
||||
| RFP-01 | 신규 큐시트 플랫폼 API 연동 | Mock 데이터 수신 흐름 구현 | `AutomationWorkspace.CueSheets`, `RefreshCueSheetCommand` |
|
||||
| RFP-01 | 신규 큐시트 플랫폼 API 연동 | JSON Mock 데이터 수신 흐름 구현 | `Data/PocWorkspace.json`, `AutomationWorkspace.CueSheets`, `RefreshCueSheetCommand` |
|
||||
| RFP-02 | ERP 편성데이터 연동 | 연동 엔드포인트 자리 표시 | `IntegrationEndpointViewModel` |
|
||||
| RFP-03 | CG 포맷 제작 자동화, Data Field Mapping | 큐시트 필드와 Scene 객체 매핑 구현 | `SceneTemplateDefinition`, `PocAutomationEngine.GenerateScene` |
|
||||
| RFP-04 | Tornado Scene API | Scene visible Text/Image 스냅샷 샘플 구현 | `SceneDataSnapshot.ToPreviewJson` |
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
## 다음 구현 후보
|
||||
|
||||
- 큐시트/ERP Mock 데이터를 JSON 파일로 분리하여 실제 API 응답 구조와 맞춘다.
|
||||
- ERP Mock 데이터를 JSON 파일로 분리하여 실제 편성 API 응답 구조와 맞춘다.
|
||||
- Tornado2/Tornado3 어댑터를 동일 인터페이스로 유지하고, 버전별 구현체를 분리한다.
|
||||
- Scene 내부 비노출 객체를 구분할 메타데이터 규칙을 정의한다.
|
||||
- 1차 검수 실패 사유를 필드 단위로 누적하고 LLM 요청 후보로 전달한다.
|
||||
|
||||
Reference in New Issue
Block a user