IFieldsPluginInfo
This page contains the specific properties of the IFieldsPlugin
.
header
β
[ IStr, default: None
]
Header of the plugin.
If it is None
, we will use the registered name of the plugin as the header (with the first letter capitalized).
definitions
β
[ Dict[str, IFieldDefinition], default: None
]
Field definitions, this is what we customize most.
The keys of this property will be the keys of the extraData
. Pseudo code:
class Plugin(IFieldsPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
...,
pluginInfo=IFieldsPluginInfo(definitions=dict(
a=...,
b=...,
c=...,
)),
)
async def process(self, data: ISocketRequest):
a = data.extraData["a"]
b = data.extraData["b"]
c = data.extraData["c"]
...
numColumns
β
[ int | None, default: None
]
Number of columns that will be used to arrange the input fields.
closeOnSubmit
β
[ bool, default: True
]
Whether close the expand panel
when the submit button is clicked.
toastOnSubmit
β
[ bool, default: True
]
Whether trigger a toast message when the submit button is clicked.
toastMessageOnSubmit
β
[ str, default: None
]
The message of the toast.
- If it is
None
, default toast message will be used. - Only take effect when toastOnSubmit is
True
.
Available Fieldsβ
There are plenty of available fields and they should be able to cover most of your use cases.
IBaseField
β
Every I*Field
inherit from IBaseField
, and they will all share the following common properties:
label
β
[ IStr | None, default: None
]
The label of the field.
Different fields may render the label differently, but we'll make sure the label is noticable.
tooltip
β
[ IStr | None, default: None
]
The tooltip of the field.
Different fields may have different tooltip trigger area, but we'll make sure the trigger area is natural.
props
β
[ IChakra | None, default: None
]
Extra chakra
props for the component.
numRows
β
[ int | None, default: None
]
Number of rows that will be occupied by this field.
This is useful when we want our field to be larger. Typically, we can set it to a number not smaller than 2
to make the ITextField
larger, so users can input text more comfortably.
condition
β
[ str | None, default: None
]
Whether the field is conditioned on another field (i.e., show this field only when the condition
field has a True
value).
This is useful when the settings are hierarchical. For example, we may want to show the model
field only when the useModel
field has a True
value.
ITextField
β
This is used to collect a piece of text from the user.
default
β
[ IStr, default: None
]
Default text of the field.
IImageField
β
This is used to collect an image url from the user.
default
β
[ IStr, default: None
]
Default url of the field.
INumberField
β
This is used to collect a number from the user.
default
β
[ float, required ]
Default value of the field.
min
β
[ float | None, default: None
]
Minimum value of the field.
max
β
[ float | None, default: None
]
Maximum value of the field.
If min
& max
are both provided, we will render a Slider instead of a number Input.
step
β
[ float | None, default: None
]
Step of the Slider, only take effect when min
& max
are both provided.
isInt
β
[ bool | None, default: None
]
Whether the number should be an integer.
scale
β
[ NumberScale | None, default: None
]
Scale of the number.
class NumberScale(str, Enum):
LINEAR = "linear"
LOGARITHMIC = "logarithmic"
precision
β
[ int | None, default: None
]
Precision of the Slider caption, only take effect when min
& max
are both provided.
ISelectField
β
This is used to collect a / some selection(s) from the user.
options
β
[ List[IStr], required ]
The options of the field.
default
β
[ IStr, required ]
The default value of the field.
isMulti
β
[ bool | None, default: None
]
Whether use multi-select.
Currently multi-select is not supported.
I18NSelectField
β
This is mainly for accessibility when we want to use I18N
as the options.
class I18NSelectField(IBaseField):
mapping: Union[Dict[str, I18N], str] = Field(
...,
description=(
"The mapping of the options. "
"The key is the 'actual' option, and the value is the i18n object to be displayed\n"
"> If `str` is provided, it represents the path to the mapping json file."
),
)
default: str = Field(..., description="The default 'actual' option of the field")
isMulti: Optional[bool] = Field(None, description="Whether use multi-select")
mapping
β
[ Dict[str, I18N], required ]
The mapping of the options. The key is the actual
option, and the value is the I18N
object to be displayed.
You can assign this field with an absolute path to a json file, and we'll dynamically load the mapping from it.
This is extremely useful when we want to hot-reload the select options without restarting the server.
default
β
[ str, required ]
The default actual
option of the field.
isMulti
β
[ bool | None, default: None
]
Whether use multi-select.
Currently multi-select is not supported.
Exampleβ
To use I18NSelectField
, we often need to define the 'field' separately:
from cfdraw import *
foo_field = I18NSelectField(
mapping=dict(
bar1=I18N(zh="bar1_δΈζ", en="bar1_en"),
bar2=I18N(zh="bar2_δΈζ", en="bar2_en"),
),
default="bar2",
)
Let's break it down. First, the mapping
:
from cfdraw import *
foo_field = I18NSelectField(
mapping=dict(
bar1=I18N(zh="bar1_δΈζ", en="bar1_en"),
bar2=I18N(zh="bar2_δΈζ", en="bar2_en"),
),
default="bar2",
)
indicates that there will be two options: bar1
and bar2
, and:
- The
bar1
option will be displayed asbar1_δΈζ
in Chinese andbar1_en
in English. - The
bar2
option will be displayed asbar2_δΈζ
in Chinese andbar2_en
in English.
Then, the default
:
from cfdraw import *
foo_field = I18NSelectField(
mapping=dict(
bar1=I18N(zh="bar1_δΈζ", en="bar1_en"),
bar2=I18N(zh="bar2_δΈζ", en="bar2_en"),
),
default="bar2",
)
indicates that the default option is bar2
.
Here's the complete code that utilizes this foo_field
:
from cfdraw import *
foo_field = I18NSelectField(
mapping=dict(
bar1=I18N(zh="bar1_δΈζ", en="bar1_en"),
bar2=I18N(zh="bar2_δΈζ", en="bar2_en"),
),
default="bar2",
)
class Plugin(IFieldsPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
w=300,
h=180,
pivot=PivotType.LEFT,
pluginInfo=IFieldsPluginInfo(definitions=dict(foo=foo_field)),
)
async def process(self, data: ISocketRequest) -> str:
foo_i18n_d = data.extraData["foo"]
foo = foo_field.parse(foo_i18n_d)
return f"foo: {foo}"
register_plugin("foo")(Plugin)
app = App()
As the highlighted lines shows:
- In
settings
, we define thefoo_field
as thefoo
field of the plugin. - In
process
, we first get theI18N
object from thefoo
key ofextraData
, then we use theparse
method of thefoo_field
to get theactual
option.
And here's a demo video of how this plugin works:
ISelectLocalField
β
This is used to collect local files specified by the user.
This is handy when we need to load local models for the plugin.
path
β
[ str, required ]
The local path that you want to read from.
default
β
[ str, required ]
The default value of the field.
regex
β
[ str, required ]
The regex to filter the files / folders.
noExt
β
[ bool, required ]
Whether to remove the extension.
onlyFiles
β
[ bool, required ]
Whether only consider the files.
defaultPlaceholder
β
[ str, required ]
If provided, it will be inserted to the first of the options and serve as the default value.
isMulti
β
[ bool, required ]
Whether use multi-select.
Currently multi-select is not supported.
See Example for the usage of this field.
IBooleanField
β
This is used to collect a boolean flag from the user.
default
β
[ bool, required ]
The default value of the field.
IColorField
β
This is used to collect a color from the user.
default
β
[ IStr, default: "#ffffff"
]
The default value of the field.
IListField
β
This is used to collect a list of 'forms' from the user.
This is handy if the corresponding field can be 'stacked' (e.g., multi LoRA, multi ControlNet).
item
β
[ Dict[str, IFieldDefinition], required ]
The definition of the 'form'.
displayKey
β
[ str, default: None
]
The key of the field to be displayed when collapsed.
default
β
[ List[Any], default: []
]
The default value of the field.
In most cases, default
should be an empty list.
Exampleβ
Let's show an example on how to implement a field which aims to support multi LoRA:
from cfdraw import *
from pathlib import Path
lora_field = IListField(
item=dict(
model=ISelectLocalField(
path=str(Path(__file__).parent / "lora"),
noExt=True,
onlyFiles=True,
regex=".*\\.safetensors",
defaultPlaceholder="None",
),
strength=INumberField(
default=1.0,
min=0.0,
max=4.0,
step=0.1,
precision=1,
),
),
)
Let's break it down. First, the model
:
lora_field = IListField(
item=dict(
model=ISelectLocalField(
path=str(Path(__file__).parent / "lora"),
noExt=True,
onlyFiles=True,
regex=".*\\.safetensors",
defaultPlaceholder="None",
),
...
),
)
These codes do the following things:
- We'll read the files from the
lora
folder in the same directory ofapp.py
. - The extensions will not be used.
- Only files will be considered.
- Only files with the extension
.safetensors
will be considered. - We'll add a
None
option to the first of the options, and it will be the default value.
Then, the strength
:
lora_field = IListField(
item=dict(
...,
strength=INumberField(
default=1.0,
min=0.0,
max=4.0,
step=0.1,
precision=1,
),
),
)
Nothing special, just a common use case of INumberField
.
Now, let's see the complete code on how to use this field:
import json
from cfdraw import *
from pathlib import Path
lora_field = IListField(
item=dict(
model=ISelectLocalField(
path=str(Path(__file__).parent / "lora"),
noExt=True,
onlyFiles=True,
regex=".*\\.safetensors",
defaultPlaceholder="None",
),
strength=INumberField(
default=1.0,
min=0.0,
max=4.0,
step=0.1,
precision=1,
),
),
)
class Plugin(IFieldsPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
w=400,
h=300,
pivot=PivotType.LEFT,
useModal=True,
pluginInfo=IFieldsPluginInfo(definitions=dict(foo=lora_field)),
)
async def process(self, data: ISocketRequest) -> str:
json_str = json.dumps(data.extraData["foo"], indent=2)
return f"foo: {json_str}"
register_plugin("foo")(Plugin)
app = App()
As the highlighted lines shows:
- In
settings
, we define thelora_field
as thefoo
field of the plugin. - In
process
, we dumps the object of thefoo
field to a JSON string.
And here's a demo video of how this plugin works: