Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ private void DrawCatalogSection(UnityResourceRagEditorSettings settings)
string catalogPath = ResourceCatalogStorage.ResolveProjectPath(null, ResourceCatalogStorage.DefaultCatalogRelativePath);
string manifestPath = ResourceCatalogStorage.ResolveProjectPath(null, ResourceCatalogStorage.DefaultManifestRelativePath);
string previewPath = ResourceCatalogStorage.ResolveProjectPath(null, ResourceCatalogStorage.DefaultPreviewRelativePath);
bool hasCatalogArtifacts = File.Exists(catalogPath) || File.Exists(manifestPath);
string catalogButtonLabel = hasCatalogArtifacts ? "카탈로그 재생성" : "카탈로그 생성";

EditorGUILayout.Space(10f);
EditorGUILayout.LabelField("카탈로그 확인", EditorStyles.boldLabel);
Expand All @@ -229,7 +231,7 @@ private void DrawCatalogSection(UnityResourceRagEditorSettings settings)
{
using (new EditorGUI.DisabledScope(_isReadinessRunning || _isBuildRunning || _isCaptureRunning || _isRepairRunning || _isBootstrapRunning))
{
if (GUILayout.Button("카탈로그 재생성", GUILayout.Height(24f), GUILayout.Width(132f)))
if (GUILayout.Button(catalogButtonLabel, GUILayout.Height(24f), GUILayout.Width(132f)))
{
RunCatalogReindex(settings);
}
Expand Down
7 changes: 6 additions & 1 deletion pipeline/mcp/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ def _search_catalog_records(


def _candidate_from_record(record: dict[str, Any], *, reason: str) -> dict[str, Any]:
return {
candidate = {
"id": record.get("id"),
"guid": record.get("guid"),
"localFileId": record.get("localFileId"),
Expand All @@ -755,6 +755,11 @@ def _candidate_from_record(record: dict[str, Any], *, reason: str) -> dict[str,
"scoreBreakdown": {},
"reasons": [reason],
}
for key in ("preview", "embeddingRefs", "prefabSummary"):
value = record.get(key)
if value not in (None, "", [], {}):
candidate[key] = value
return candidate


def _candidate_score(candidate: dict[str, Any] | None) -> float:
Expand Down
7 changes: 6 additions & 1 deletion pipeline/retrieval/search_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def score_record(
if ((record.get("uiHints") or {}).get("isRepeatableBlock")):
reasons.append("repeatable-block")

return {
result = {
"id": record.get("id"),
"guid": record.get("guid"),
"localFileId": record.get("localFileId"),
Expand All @@ -174,6 +174,11 @@ def score_record(
},
"reasons": reasons,
}
for key in ("preview", "embeddingRefs", "prefabSummary"):
value = record.get(key)
if value not in (None, "", [], {}):
result[key] = value
return result


def search(
Expand Down
9 changes: 7 additions & 2 deletions pipeline/retrieval/vector_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,19 @@ def build_tfidf_index(records: list[dict[str, Any]]) -> dict[str, Any]:
documents: list[dict[str, Any]] = []
for record, tokens in zip(records, document_tokens):
embedding_refs = record.get("embeddingRefs") or {}
documents.append({
document = {
"id": record.get("id"),
"textEmbeddingId": embedding_refs.get("textEmbeddingId") or record.get("id"),
"path": record.get("path"),
"name": record.get("name"),
"assetType": record.get("assetType"),
"vector": build_sparse_tfidf_vector(tokens, idf),
})
}
if embedding_refs.get("imageEmbeddingId"):
document["imageEmbeddingId"] = embedding_refs.get("imageEmbeddingId")
if record.get("preview"):
document["preview"] = record.get("preview")
documents.append(document)

return {
"generatedAtUtc": datetime.now(timezone.utc).isoformat(),
Expand Down
34 changes: 33 additions & 1 deletion tests/test_catalog_draft_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

from pipeline.mcp.tools import run_catalog_draft_ui_build
from pipeline.mcp.tools import _candidate_from_record, run_catalog_draft_ui_build


def _tool_payload(result: dict[str, object]) -> dict[str, object]:
Expand All @@ -34,6 +34,38 @@ def _write_catalog(path: Path, records: list[dict[str, object]]) -> None:


class CatalogDraftToolTests(unittest.TestCase):
def test_fallback_candidate_keeps_prefab_preview_metadata(self) -> None:
candidate = _candidate_from_record(
{
"id": "prefab-shell",
"guid": "guid-prefab-shell",
"path": "Assets/UI/PF_RewardPopup.prefab",
"assetType": "Prefab",
"name": "PF_RewardPopup",
"semanticText": "reward popup modal dialog shell window frame",
"preview": {
"path": "Library/ResourceRag/previews/guid-prefab-shell_100100.png",
"width": 256,
"height": 128,
},
"embeddingRefs": {
"imageEmbeddingId": "prefab-shell-preview",
"textEmbeddingId": "prefab-shell",
},
"prefabSummary": {
"rootName": "PF_RewardPopup",
"componentTypes": ["RectTransform"],
"childPaths": ["PF_RewardPopup"],
},
"binding": {"kind": "prefab", "unityLoadPath": "Assets/UI/PF_RewardPopup.prefab"},
},
reason="prefab-fallback",
)

self.assertEqual(candidate["preview"]["path"], "Library/ResourceRag/previews/guid-prefab-shell_100100.png")
self.assertEqual(candidate["embeddingRefs"]["imageEmbeddingId"], "prefab-shell-preview")
self.assertEqual(candidate["prefabSummary"]["rootName"], "PF_RewardPopup")

def test_run_catalog_draft_ui_build_reindexes_and_applies_prefab_shell(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
Expand Down
73 changes: 73 additions & 0 deletions tests/test_retrieval_search_catalog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from __future__ import annotations

import sys
import unittest
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

from pipeline.retrieval.search_catalog import Query, search
from pipeline.retrieval.vector_index import build_tfidf_index


def _prefab_record() -> dict[str, object]:
return {
"id": "inventory_panel",
"guid": "prefab-guid",
"localFileId": 100100,
"name": "PF_InventoryPanel",
"path": "Assets/UI/PF_InventoryPanel.prefab",
"assetType": "Prefab",
"binding": {"kind": "prefab", "unityLoadPath": "Assets/UI/PF_InventoryPanel.prefab"},
"semanticText": "inventory list panel shell reusable prefab",
"preview": {
"path": "Library/ResourceRag/previews/prefab-guid_100100.png",
"width": 256,
"height": 128,
},
"embeddingRefs": {
"imageEmbeddingId": "inventory_panel_preview",
"textEmbeddingId": "inventory_panel",
},
"prefabSummary": {
"rootName": "PF_InventoryPanel",
"componentTypes": ["RectTransform", "VerticalLayoutGroup"],
"childPaths": ["PF_InventoryPanel", "PF_InventoryPanel/Rows"],
},
}


class RetrievalSearchCatalogTests(unittest.TestCase):
def test_vector_index_documents_keep_prefab_preview_references(self) -> None:
vector_index = build_tfidf_index([_prefab_record()])

document = vector_index["documents"][0]

self.assertEqual(document["imageEmbeddingId"], "inventory_panel_preview")
self.assertEqual(document["preview"]["path"], "Library/ResourceRag/previews/prefab-guid_100100.png")

def test_search_results_keep_prefab_preview_metadata_for_reuse(self) -> None:
record = _prefab_record()

results = search(
Query(
query_text="inventory reusable panel",
region_type="inventory",
preferred_kind="prefab",
aspect_ratio=None,
top_k=1,
),
[record],
{"inventory_panel": 1.0},
)

self.assertEqual(results[0]["preview"]["path"], "Library/ResourceRag/previews/prefab-guid_100100.png")
self.assertEqual(results[0]["embeddingRefs"]["imageEmbeddingId"], "inventory_panel_preview")
self.assertEqual(results[0]["prefabSummary"]["rootName"], "PF_InventoryPanel")


if __name__ == "__main__":
unittest.main()
8 changes: 8 additions & 0 deletions tests/test_unity_package_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
REPO_ROOT = Path(__file__).resolve().parents[1]
PACKAGE_ROOT = REPO_ROOT / "Packages" / "com.hanjo92.unity-resource-rag"
APPLY_TOOL_PATH = PACKAGE_ROOT / "Editor" / "ResourceIndexing" / "ApplyUiBlueprintTool.cs"
WINDOW_PATH = PACKAGE_ROOT / "Editor" / "UnityResourceRagWindow.cs"
PACKAGE_JSON_PATH = PACKAGE_ROOT / "package.json"
PACKAGE_README_PATH = PACKAGE_ROOT / "README.md"
PACKAGE_DOC_README_PATH = PACKAGE_ROOT / "Documentation~" / "README.md"
Expand Down Expand Up @@ -49,6 +50,13 @@ def test_sample_readme_marks_project_specific_dependencies(self) -> None:
self.assertIn("MyGame.UI.SafeAreaFitter", text)
self.assertIn("프로젝트 전용 예시", text)

def test_catalog_window_exposes_initial_create_action(self) -> None:
source = WINDOW_PATH.read_text(encoding="utf-8")

self.assertIn('bool hasCatalogArtifacts = File.Exists(catalogPath) || File.Exists(manifestPath);', source)
self.assertIn('string catalogButtonLabel = hasCatalogArtifacts ? "카탈로그 재생성" : "카탈로그 생성";', source)
self.assertIn("GUILayout.Button(catalogButtonLabel", source)


if __name__ == "__main__":
unittest.main()
Loading