Merge branch 'add_emoji_icon' into dev

This commit is contained in:
cristhianzl 2024-02-08 18:08:24 -03:00
commit 33d05a23f3
6 changed files with 47 additions and 14 deletions

View file

@ -3,9 +3,9 @@ import operator
import warnings import warnings
from typing import Any, ClassVar, Optional from typing import Any, ClassVar, Optional
import emoji
from cachetools import TTLCache, cachedmethod from cachetools import TTLCache, cachedmethod
from fastapi import HTTPException from fastapi import HTTPException
from langflow.interface.custom.code_parser import CodeParser from langflow.interface.custom.code_parser import CodeParser
from langflow.utils import validate from langflow.utils import validate
@ -35,6 +35,10 @@ class Component:
else: else:
setattr(self, key, value) setattr(self, key, value)
# Validate the emoji at the icon field
if self.icon:
self.icon = self.validate_icon(self.icon)
def __setattr__(self, key, value): def __setattr__(self, key, value):
if key == "_user_id" and hasattr(self, "_user_id"): if key == "_user_id" and hasattr(self, "_user_id"):
warnings.warn("user_id is immutable and cannot be changed.") warnings.warn("user_id is immutable and cannot be changed.")
@ -82,7 +86,22 @@ class Component:
elif "documentation" in item_name: elif "documentation" in item_name:
template_config["documentation"] = ast.literal_eval(item_value) template_config["documentation"] = ast.literal_eval(item_value)
elif "icon" in item_name:
icon_str = ast.literal_eval(item_value)
template_config["icon"] = self.validate_icon(icon_str)
return template_config return template_config
def validate_icon(self, value: str):
# we are going to use the emoji library to validate the emoji
# emojis can be defined using the :emoji_name: syntax
if not value.startswith(":") or not value.endswith(":"):
raise ValueError("Invalid emoji. Please use the :emoji_name: syntax.")
emoji_value = emoji.emojize(value, variant="emoji_type")
if value == emoji_value:
raise ValueError(f"Invalid emoji. {value} is not a valid emoji.")
return emoji_value
def build(self, *args: Any, **kwargs: Any) -> Any: def build(self, *args: Any, **kwargs: Any) -> Any:
raise NotImplementedError raise NotImplementedError

View file

@ -10,25 +10,31 @@ from langflow.interface.custom.code_parser.utils import (
extract_inner_type_from_generic_alias, extract_inner_type_from_generic_alias,
extract_union_types_from_generic_alias, extract_union_types_from_generic_alias,
) )
from langflow.interface.custom.custom_component.component import Component
from langflow.services.database.models.flow import Flow from langflow.services.database.models.flow import Flow
from langflow.services.database.utils import session_getter from langflow.services.database.utils import session_getter
from langflow.services.deps import get_credential_service, get_db_service from langflow.services.deps import get_credential_service, get_db_service
from langflow.utils import validate from langflow.utils import validate
from .component import Component
class CustomComponent(Component): class CustomComponent(Component):
display_name: Optional[str] = None display_name: Optional[str] = None
"""The display name of the component. Defaults to None."""
description: Optional[str] = None description: Optional[str] = None
"""The description of the component. Defaults to None."""
icon: Optional[str] = None
"""The icon of the component. It should be an emoji. Defaults to None."""
code: Optional[str] = None code: Optional[str] = None
"""The code of the component. Defaults to None."""
field_config: dict = {} field_config: dict = {}
"""The field configuration of the component. Defaults to an empty dictionary."""
code_class_base_inheritance: ClassVar[str] = "CustomComponent" code_class_base_inheritance: ClassVar[str] = "CustomComponent"
function_entrypoint_name: ClassVar[str] = "build" function_entrypoint_name: ClassVar[str] = "build"
function: Optional[Callable] = None function: Optional[Callable] = None
repr_value: Optional[Any] = "" repr_value: Optional[Any] = ""
user_id: Optional[Union[UUID, str]] = None user_id: Optional[Union[UUID, str]] = None
status: Optional[Any] = None status: Optional[Any] = None
"""The status of the component. This is displayed on the frontend. Defaults to None."""
_tree: Optional[dict] = None _tree: Optional[dict] = None
def __init__(self, **data): def __init__(self, **data):

View file

@ -7,6 +7,8 @@ from typing import Any, Dict, List, Optional, Union
from uuid import UUID from uuid import UUID
from fastapi import HTTPException from fastapi import HTTPException
from loguru import logger
from langflow.field_typing.range_spec import RangeSpec from langflow.field_typing.range_spec import RangeSpec
from langflow.interface.custom.code_parser.utils import extract_inner_type from langflow.interface.custom.code_parser.utils import extract_inner_type
from langflow.interface.custom.custom_component import CustomComponent from langflow.interface.custom.custom_component import CustomComponent
@ -19,7 +21,6 @@ from langflow.interface.importing.utils import eval_custom_component_code
from langflow.template.field.base import TemplateField from langflow.template.field.base import TemplateField
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
from langflow.utils.util import get_base_classes from langflow.utils.util import get_base_classes
from loguru import logger
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]): def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
@ -231,6 +232,7 @@ def sanitize_template_config(template_config):
"beta", "beta",
"documentation", "documentation",
"output_types", "output_types",
"icon",
} }
for key in template_config.copy(): for key in template_config.copy():
if key not in attributes: if key not in attributes:

View file

@ -2,13 +2,12 @@ import re
from collections import defaultdict from collections import defaultdict
from typing import ClassVar, Dict, List, Optional, Union from typing import ClassVar, Dict, List, Optional, Union
from pydantic import BaseModel, Field, field_serializer, model_serializer
from langflow.template.field.base import TemplateField from langflow.template.field.base import TemplateField
from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE, FORCE_SHOW_FIELDS from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE, FORCE_SHOW_FIELDS
from langflow.template.frontend_node.formatter import field_formatters from langflow.template.frontend_node.formatter import field_formatters
from langflow.template.template.base import Template from langflow.template.template.base import Template
from langflow.utils import constants from langflow.utils import constants
from pydantic import BaseModel, Field, field_serializer, model_serializer
class FieldFormatters(BaseModel): class FieldFormatters(BaseModel):
@ -43,6 +42,7 @@ class FrontendNode(BaseModel):
_format_template: bool = True _format_template: bool = True
template: Template template: Template
description: Optional[str] = None description: Optional[str] = None
icon: Optional[str] = None
base_classes: List[str] base_classes: List[str]
name: str = "" name: str = ""
display_name: Optional[str] = "" display_name: Optional[str] = ""

View file

@ -156,14 +156,19 @@ export default function GenericNode({
(!showNode && "justify-center") (!showNode && "justify-center")
} }
> >
<IconComponent {data?.node?.icon ? (
name={data.node?.flow ? "group_components" : name} <span className="text-lg">{data?.node?.icon}</span>
className={ ) : (
"generic-node-icon " + <IconComponent
(!showNode ? "absolute inset-x-6 h-12 w-12" : "") name={data.node?.flow ? "group_components" : name}
} className={
iconColor={`${nodeColors[types[data.type]]}`} "generic-node-icon " +
/> (!showNode ? "absolute inset-x-6 h-12 w-12" : "")
}
iconColor={`${nodeColors[types[data.type]]}`}
/>
)}
{showNode && ( {showNode && (
<div className="generic-node-tooltip-div"> <div className="generic-node-tooltip-div">
{nameEditable && inputName ? ( {nameEditable && inputName ? (

View file

@ -17,6 +17,7 @@ export type APIClassType = {
description: string; description: string;
template: APITemplateType; template: APITemplateType;
display_name: string; display_name: string;
icon?: string;
input_types?: Array<string>; input_types?: Array<string>;
output_types?: Array<string>; output_types?: Array<string>;
custom_fields?: CustomFieldsType; custom_fields?: CustomFieldsType;