diff --git a/.roo/mcp.json b/.roo/mcp.json new file mode 100644 index 0000000..ca3d3f3 --- /dev/null +++ b/.roo/mcp.json @@ -0,0 +1,45 @@ +{ + "mcpServers": { + "conport": { + "command": "C:\\Users\\theis\\context-portal\\.venv\\Scripts\\python.exe", + "args": [ + "C:\\Users\\theis\\context-portal\\src\\context_portal_mcp\\main.py", + "--mode", + "stdio", + "--workspace_id", + "${workspaceFolder}" + ], + "alwaysAllow": [ + "get_product_context", + "update_product_context", + "get_active_context", + "update_active_context", + "log_decision", + "get_decisions", + "search_decisions_fts", + "log_progress", + "get_progress", + "update_progress", + "delete_progress_by_id", + "log_system_pattern", + "get_system_patterns", + "log_custom_data", + "get_custom_data", + "delete_custom_data", + "search_project_glossary_fts", + "export_conport_to_markdown", + "import_markdown_to_conport", + "link_conport_items", + "search_custom_data_value_fts", + "get_linked_items", + "batch_log_items", + "get_item_history", + "delete_decision_by_id", + "delete_system_pattern_by_id", + "get_conport_schema", + "get_recent_activity_summary", + "semantic_search_conport" + ] + } + } +} \ No newline at end of file diff --git a/TestFiles/Test-BoucleChunky001.json b/TestFiles/Test-BoucleChunky001.json index 770d458..292d275 100644 --- a/TestFiles/Test-BoucleChunky001.json +++ b/TestFiles/Test-BoucleChunky001.json @@ -26,7 +26,7 @@ }, { "file_path": "BoucleChunky001_DISP_1K_METALNESS.png", - "item_type": "MAP_DISP", + "item_type": "EXTRA", "target_asset_name_override": "BoucleChunky001" }, { diff --git a/autotest.py b/autotest.py index 96f147e..15771e3 100644 --- a/autotest.py +++ b/autotest.py @@ -584,63 +584,59 @@ class AutoTester(QObject): logger.error(f"Value mismatch for field '{key}' in {item_type_name} ({current_context}): Actual='{actual_value}', Expected='{expected_value}'.") item_match = False - return item_match - - def _compare_list_of_rules(self, actual_list: List[Dict[str, Any]], expected_list: List[Dict[str, Any]], item_type_name: str, parent_context: str, item_key_field: str) -> bool: - """ - Compares a list of actual rule items against a list of expected rule items. - Items are matched by a key field (e.g., 'asset_name' or 'file_path'). - Order independent for matching, but logs count mismatches. - """ - list_match = True # Corrected indentation - if not isinstance(actual_list, list) or not isinstance(expected_list, list): - logger.error(f"Type mismatch for list of {item_type_name}s in {parent_context}. Expected lists.") - return False - - if len(actual_list) != len(expected_list): - logger.error(f"Mismatch in number of {item_type_name}s for {parent_context}. Actual: {len(actual_list)}, Expected: {len(expected_list)}.") - list_match = False # Count mismatch is an error - # If counts differ, we still try to match what we can to provide more detailed feedback, - # but the overall list_match will remain False. - - actual_items_map = {item.get(item_key_field): item for item in actual_list if item.get(item_key_field) is not None} - - # Keep track of expected items that found a match to identify missing ones more easily - matched_expected_keys = set() - - for expected_item in expected_list: - expected_key_value = expected_item.get(item_key_field) - if expected_key_value is None: - logger.error(f"Expected {item_type_name} in {parent_context} is missing key field '{item_key_field}'. Cannot compare this item: {expected_item}") - list_match = False # This specific expected item cannot be processed - continue - - actual_item = actual_items_map.get(expected_key_value) - if actual_item: - matched_expected_keys.add(expected_key_value) - if not self._compare_rule_item(actual_item, expected_item, item_type_name, parent_context): - list_match = False # Individual item comparison failed - else: - logger.error(f"Expected {item_type_name} with {item_key_field} '{expected_key_value}' not found in actual items for {parent_context}.") - list_match = False - - # Identify actual items that were not matched by any expected item - # This is useful if len(actual_list) >= len(expected_list) but some actual items are "extra" - for actual_key_value, actual_item_data in actual_items_map.items(): - if actual_key_value not in matched_expected_keys: - logger.debug(f"Extra actual {item_type_name} with {item_key_field} '{actual_key_value}' found in {parent_context} (not in expected list or already matched).") - if len(actual_list) != len(expected_list): # If counts already flagged a mismatch, this is just detail - pass - else: # Counts matched, but content didn't align perfectly by key - list_match = False - - - return list_match # Corrected indentation - - def _compare_rules(self, actual_rules_data: Dict[str, Any], expected_rules_data: Dict[str, Any]) -> bool: # Corrected structure: moved out - item_match = False - return item_match + + def _compare_list_of_rules(self, actual_list: List[Dict[str, Any]], expected_list: List[Dict[str, Any]], item_type_name: str, parent_context: str, item_key_field: str) -> bool: + """ + Compares a list of actual rule items against a list of expected rule items. + Items are matched by a key field (e.g., 'asset_name' or 'file_path'). + Order independent for matching, but logs count mismatches. + """ + list_match = True + if not isinstance(actual_list, list) or not isinstance(expected_list, list): + logger.error(f"Type mismatch for list of {item_type_name}s in {parent_context}. Expected lists.") + return False + + if len(actual_list) != len(expected_list): + logger.error(f"Mismatch in number of {item_type_name}s for {parent_context}. Actual: {len(actual_list)}, Expected: {len(expected_list)}.") + list_match = False # Count mismatch is an error + # If counts differ, we still try to match what we can to provide more detailed feedback, + # but the overall list_match will remain False. + + actual_items_map = {item.get(item_key_field): item for item in actual_list if item.get(item_key_field) is not None} + + # Keep track of expected items that found a match to identify missing ones more easily + matched_expected_keys = set() + + for expected_item in expected_list: + expected_key_value = expected_item.get(item_key_field) + if expected_key_value is None: + logger.error(f"Expected {item_type_name} in {parent_context} is missing key field '{item_key_field}'. Cannot compare this item: {expected_item}") + list_match = False # This specific expected item cannot be processed + continue + + actual_item = actual_items_map.get(expected_key_value) + if actual_item: + matched_expected_keys.add(expected_key_value) + if not self._compare_rule_item(actual_item, expected_item, item_type_name, parent_context): + list_match = False # Individual item comparison failed + else: + logger.error(f"Expected {item_type_name} with {item_key_field} '{expected_key_value}' not found in actual items for {parent_context}.") + list_match = False + + # Identify actual items that were not matched by any expected item + # This is useful if len(actual_list) >= len(expected_list) but some actual items are "extra" + for actual_key_value, actual_item_data in actual_items_map.items(): + if actual_key_value not in matched_expected_keys: + logger.debug(f"Extra actual {item_type_name} with {item_key_field} '{actual_key_value}' found in {parent_context} (not in expected list or already matched).") + if len(actual_list) != len(expected_list): # If counts already flagged a mismatch, this is just detail + pass + else: # Counts matched, but content didn't align perfectly by key + list_match = False + + + return list_match + def _compare_rules(self, actual_rules_data: Dict[str, Any], expected_rules_data: Dict[str, Any]) -> bool: """ diff --git a/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/data_level0.bin b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/data_level0.bin new file mode 100644 index 0000000..09cffb6 Binary files /dev/null and b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/data_level0.bin differ diff --git a/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/header.bin b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/header.bin new file mode 100644 index 0000000..e85f465 Binary files /dev/null and b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/header.bin differ diff --git a/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/length.bin b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/length.bin new file mode 100644 index 0000000..bb1821a Binary files /dev/null and b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/length.bin differ diff --git a/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/link_lists.bin b/context_portal/conport_vector_data/3712b223-f80b-4c07-b57a-5cf7c8175c86/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/context_portal/conport_vector_data/chroma.sqlite3 b/context_portal/conport_vector_data/chroma.sqlite3 new file mode 100644 index 0000000..bfcc371 Binary files /dev/null and b/context_portal/conport_vector_data/chroma.sqlite3 differ diff --git a/context_portal/context.db b/context_portal/context.db new file mode 100644 index 0000000..611eda0 Binary files /dev/null and b/context_portal/context.db differ diff --git a/projectBrief.md b/projectBrief.md new file mode 100644 index 0000000..8ceb261 --- /dev/null +++ b/projectBrief.md @@ -0,0 +1,44 @@ +# Project Brief: Asset Processor Tool + +## 1. Main Goal & Purpose + +The primary goal of the Asset Processor Tool is to provide **CG artists and 3D content teams with a friendly, fast, and flexible interface to process and organize 3D asset source files into a standardized library format.** It automates repetitive and complex tasks involved in preparing assets from various suppliers for use in production pipelines. + +## 2. Key Features & Components + +* **Automated Asset Processing:** Ingests 3D asset source files (texture sets, models, etc.) from `.zip`, `.rar`, `.7z` archives, or folders. +* **Preset-Driven Workflow:** Utilizes configurable JSON presets to interpret different asset sources (e.g., from various online vendors or internal standards), defining rules for file classification and processing. +* **Comprehensive File Operations:** + * **Classification:** Automatically identifies map types (Color, Normal, Roughness, etc.), models, and other file categories based on preset rules. + * **Image Processing:** Performs tasks like image resizing (to standard resolutions like 1K, 2K, 4K, avoiding upscaling), glossiness-to-roughness conversion, normal map green channel inversion (OpenGL/DirectX handling), alpha channel extraction, bit-depth adjustments, and low-resolution fallback generation for small source images. + * **Channel Merging:** Combines channels from different source maps into packed textures (e.g., Normal + Roughness + Metallic into a single NRMRGH map). +* **Metadata Generation:** Creates a detailed `metadata.json` file for each processed asset, containing information about maps, categories, processing settings, and more, for downstream tool integration. +* **Flexible Output Organization:** Generates a clean, structured output directory based on user-configurable naming patterns and tokens. +* **Multiple User Interfaces:** + * **Graphical User Interface (GUI):** The primary interface, designed to be user-friendly, offering drag-and-drop functionality, an integrated preset editor, a live preview table for rule validation and overrides, and clear processing controls. + * **Directory Monitor:** An automated script that watches a specified folder for new asset archives and processes them based on preset names embedded in the archive filename. + * **Command-Line Interface (CLI):** Intended for batch processing and scripting (currently with limited core functionality). +* **Optional Blender Integration:** Can automatically run Blender scripts post-processing to create PBR node groups and materials in specified `.blend` files, linking to the newly processed textures. +* **Hierarchical Rule System:** Allows for dynamic, granular overrides of preset configurations at the source, asset, or individual file level via the GUI. +* **Experimental LLM Prediction:** Includes an option to use a Large Language Model for file interpretation and rule prediction. + +## 3. Target Audience + +* **CG Artists:** Individual artists looking for an efficient way to manage and prepare their personal or downloaded asset libraries. +* **3D Content Creation Teams:** Studios or groups needing a standardized pipeline for processing and organizing assets from multiple sources. +* **Technical Artists/Pipeline Developers:** Who may extend or integrate the tool into broader production workflows. + +## 4. Overall Architectural Style & Key Technologies + +* **Core Language:** Python +* **GUI Framework:** PySide6 +* **Configuration:** Primarily JSON-based (application settings, user overrides, type definitions, supplier settings, presets, LLM settings). +* **Processing Architecture:** A modular, staged processing pipeline orchestrated by a central engine. Each stage performs a discrete task on an `AssetProcessingContext` object. +* **Key Libraries:** OpenCV (image processing), NumPy (numerical operations), py7zr/rarfile (archive handling), watchdog (directory monitoring). +* **Design Principles:** Modularity, configurability, and user-friendliness (especially for the GUI). + +## 5. Foundational Information + +* The tool aims to significantly reduce manual effort and ensure consistency in asset preparation. +* It is designed to be adaptable to various asset sources and pipeline requirements through its extensive configuration options and preset system. +* The output `metadata.json` is key for enabling further automation and integration with other tools or digital content creation (DCC) applications. \ No newline at end of file