| from loguru import logger |
|
|
| from langflow.custom.directory_reader import DirectoryReader |
| from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode |
|
|
|
|
| def merge_nested_dicts_with_renaming(dict1, dict2): |
| for key, value in dict2.items(): |
| if key in dict1 and isinstance(value, dict) and isinstance(dict1.get(key), dict): |
| for sub_key, sub_value in value.items(): |
| |
| |
| |
| |
| dict1[key][sub_key] = sub_value |
| else: |
| dict1[key] = value |
| return dict1 |
|
|
|
|
| def build_invalid_menu(invalid_components): |
| """Build the invalid menu.""" |
| if not invalid_components.get("menu"): |
| return {} |
|
|
| logger.debug("------------------- INVALID COMPONENTS -------------------") |
| invalid_menu = {} |
| for menu_item in invalid_components["menu"]: |
| menu_name = menu_item["name"] |
| invalid_menu[menu_name] = build_invalid_menu_items(menu_item) |
| return invalid_menu |
|
|
|
|
| def build_valid_menu(valid_components): |
| """Build the valid menu.""" |
| valid_menu = {} |
| logger.debug("------------------- VALID COMPONENTS -------------------") |
| for menu_item in valid_components["menu"]: |
| menu_name = menu_item["name"] |
| valid_menu[menu_name] = build_menu_items(menu_item) |
| return valid_menu |
|
|
|
|
| def build_and_validate_all_files(reader: DirectoryReader, file_list): |
| """Build and validate all files.""" |
| data = reader.build_component_menu_list(file_list) |
|
|
| valid_components = reader.filter_loaded_components(data=data, with_errors=False) |
| invalid_components = reader.filter_loaded_components(data=data, with_errors=True) |
|
|
| return valid_components, invalid_components |
|
|
|
|
| async def abuild_and_validate_all_files(reader: DirectoryReader, file_list): |
| """Build and validate all files.""" |
| data = await reader.abuild_component_menu_list(file_list) |
|
|
| valid_components = reader.filter_loaded_components(data=data, with_errors=False) |
| invalid_components = reader.filter_loaded_components(data=data, with_errors=True) |
|
|
| return valid_components, invalid_components |
|
|
|
|
| def load_files_from_path(path: str): |
| """Load all files from a given path.""" |
| reader = DirectoryReader(path, compress_code_field=False) |
|
|
| return reader.get_files() |
|
|
|
|
| def build_custom_component_list_from_path(path: str): |
| """Build a list of custom components for the langchain from a given path.""" |
| file_list = load_files_from_path(path) |
| reader = DirectoryReader(path, compress_code_field=False) |
|
|
| valid_components, invalid_components = build_and_validate_all_files(reader, file_list) |
|
|
| valid_menu = build_valid_menu(valid_components) |
| invalid_menu = build_invalid_menu(invalid_components) |
|
|
| return merge_nested_dicts_with_renaming(valid_menu, invalid_menu) |
|
|
|
|
| async def abuild_custom_component_list_from_path(path: str): |
| """Build a list of custom components for the langchain from a given path.""" |
| file_list = load_files_from_path(path) |
| reader = DirectoryReader(path, compress_code_field=False) |
|
|
| valid_components, invalid_components = await abuild_and_validate_all_files(reader, file_list) |
|
|
| valid_menu = build_valid_menu(valid_components) |
| invalid_menu = build_invalid_menu(invalid_components) |
|
|
| return merge_nested_dicts_with_renaming(valid_menu, invalid_menu) |
|
|
|
|
| def create_invalid_component_template(component, component_name): |
| """Create a template for an invalid component.""" |
| component_code = component["code"] |
| component_frontend_node = CustomComponentFrontendNode( |
| description="ERROR - Check your Python Code", |
| display_name=f"ERROR - {component_name}", |
| ) |
|
|
| component_frontend_node.error = component.get("error", None) |
| field = component_frontend_node.template.get_field("code") |
| field.value = component_code |
| component_frontend_node.template.update_field("code", field) |
| return component_frontend_node.model_dump(by_alias=True, exclude_none=True) |
|
|
|
|
| def log_invalid_component_details(component) -> None: |
| """Log details of an invalid component.""" |
| logger.debug(component) |
| logger.debug(f"Component Path: {component.get('path', None)}") |
| logger.debug(f"Component Error: {component.get('error', None)}") |
|
|
|
|
| def build_invalid_component(component): |
| """Build a single invalid component.""" |
| component_name = component["name"] |
| component_template = create_invalid_component_template(component, component_name) |
| log_invalid_component_details(component) |
| return component_name, component_template |
|
|
|
|
| def build_invalid_menu_items(menu_item): |
| """Build invalid menu items for a given menu.""" |
| menu_items = {} |
| for component in menu_item["components"]: |
| try: |
| component_name, component_template = build_invalid_component(component) |
| menu_items[component_name] = component_template |
| logger.debug(f"Added {component_name} to invalid menu.") |
| except Exception: |
| logger.exception(f"Error while creating custom component [{component_name}]") |
| return menu_items |
|
|
|
|
| def get_new_key(dictionary, original_key): |
| counter = 1 |
| new_key = original_key + " (" + str(counter) + ")" |
| while new_key in dictionary: |
| counter += 1 |
| new_key = original_key + " (" + str(counter) + ")" |
| return new_key |
|
|
|
|
| def determine_component_name(component): |
| """Determine the name of the component.""" |
| |
| |
| |
| |
| |
| |
| return component["name"] |
|
|
|
|
| def build_menu_items(menu_item): |
| """Build menu items for a given menu.""" |
| menu_items = {} |
| logger.debug(f"Building menu items for {menu_item['name']}") |
| logger.debug(f"Loading {len(menu_item['components'])} components") |
| for component_name, component_template, component in menu_item["components"]: |
| try: |
| menu_items[component_name] = component_template |
| except Exception: |
| logger.exception(f"Error while building custom component {component['output_types']}") |
| return menu_items |
|
|