interactive-pipe 0.8.3__tar.gz → 0.8.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {interactive_pipe-0.8.3/src/interactive_pipe.egg-info → interactive_pipe-0.8.4}/PKG-INFO +3 -2
  2. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/pyproject.toml +1 -1
  3. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/readme.md +2 -1
  4. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/__init__.py +2 -2
  5. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/gradio_control.py +9 -7
  6. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/mpl_control.py +23 -2
  7. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/mpl_gui.py +4 -2
  8. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/qt_control.py +37 -2
  9. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/qt_gui.py +4 -1
  10. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/headless/control.py +24 -11
  11. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/control_abbreviation.py +8 -5
  12. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4/src/interactive_pipe.egg-info}/PKG-INFO +3 -2
  13. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/LICENSE +0 -0
  14. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/setup.cfg +0 -0
  15. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/__init__.py +0 -0
  16. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/cache.py +0 -0
  17. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/engine.py +0 -0
  18. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/filter.py +0 -0
  19. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/graph.py +0 -0
  20. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/pipeline.py +0 -0
  21. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/core/signature.py +0 -0
  22. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/__init__.py +0 -0
  23. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/audio.py +0 -0
  24. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/curves.py +0 -0
  25. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/data.py +0 -0
  26. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/image.py +0 -0
  27. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/data_objects/parameters.py +0 -0
  28. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/__init__.py +0 -0
  29. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/gradio_gui.py +0 -0
  30. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/gui.py +0 -0
  31. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/mpl_window.py +0 -0
  32. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/nb_control.py +0 -0
  33. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/nb_gui.py +0 -0
  34. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/graphical/window.py +0 -0
  35. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/headless/__init__.py +0 -0
  36. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/headless/keyboard.py +0 -0
  37. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/headless/pipeline.py +0 -0
  38. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/__init__.py +0 -0
  39. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/_private.py +0 -0
  40. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/choose_backend.py +0 -0
  41. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/filter_decorator.py +0 -0
  42. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/keyword_args_analyzer.py +0 -0
  43. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/helper/pipeline_decorator.py +0 -0
  44. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/thirdparty/images_openai_api.py +0 -0
  45. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe/thirdparty/music_spotify.py +0 -0
  46. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe.egg-info/SOURCES.txt +0 -0
  47. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
  48. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe.egg-info/requires.txt +0 -0
  49. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/src/interactive_pipe.egg-info/top_level.txt +0 -0
  50. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_cache.py +0 -0
  51. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_control_abbreviations.py +0 -0
  52. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_controller.py +0 -0
  53. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_core.py +0 -0
  54. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_curves.py +0 -0
  55. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_decorator.py +0 -0
  56. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_engine.py +0 -0
  57. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_filter.py +0 -0
  58. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_headless.py +0 -0
  59. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_image.py +0 -0
  60. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_parameters.py +0 -0
  61. {interactive_pipe-0.8.3 → interactive_pipe-0.8.4}/test/test_recorder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: interactive_pipe
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
5
5
  Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
@@ -106,7 +106,7 @@ pip install -e ".[full]"
106
106
 
107
107
  ## :scroll: Features
108
108
 
109
- **Version 0.8.3**
109
+ **Version 0.8.4**
110
110
  - Modular multi-image processing filters
111
111
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
112
112
  - Support in jupyter notebooks
@@ -117,6 +117,7 @@ pip install -e ".[full]"
117
117
  - :new: gradio backend (+allows sharing with others).
118
118
  - :new: Audio support in Gradio (live audio or display several players by returning 1D numpy arrays)
119
119
  - :new: Circular sliders for Qt Backend
120
+ - :new: Text prompt (`free_text=("Hello world!", None),`)
120
121
 
121
122
 
122
123
 
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "interactive_pipe"
8
- version = "0.8.3"
8
+ version = "0.8.4"
9
9
  authors = [
10
10
  { name="Balthazar Neveu", email="balthazarneveu@gmail.com" },
11
11
  ]
@@ -62,7 +62,7 @@ pip install -e ".[full]"
62
62
 
63
63
  ## :scroll: Features
64
64
 
65
- **Version 0.8.3**
65
+ **Version 0.8.4**
66
66
  - Modular multi-image processing filters
67
67
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
68
68
  - Support in jupyter notebooks
@@ -73,6 +73,7 @@ pip install -e ".[full]"
73
73
  - :new: gradio backend (+allows sharing with others).
74
74
  - :new: Audio support in Gradio (live audio or display several players by returning 1D numpy arrays)
75
75
  - :new: Circular sliders for Qt Backend
76
+ - :new: Text prompt (`free_text=("Hello world!", None),`)
76
77
 
77
78
 
78
79
 
@@ -1,6 +1,6 @@
1
- __version__ = "0.8.3"
1
+ __version__ = "0.8.4"
2
2
  from interactive_pipe.helper.pipeline_decorator import pipeline, interactive_pipeline
3
- from interactive_pipe.headless.control import Control, CircularControl
3
+ from interactive_pipe.headless.control import Control, CircularControl, TextPrompt
4
4
  from interactive_pipe.data_objects.curves import Curve, SingleCurve
5
5
  from interactive_pipe.data_objects.image import Image
6
6
  from interactive_pipe.headless.keyboard import KeyboardControl
@@ -29,7 +29,7 @@ class ControlFactory:
29
29
  bool: TickBoxControl,
30
30
  int: IntSliderControl,
31
31
  float: FloatSliderControl,
32
- str: DropdownMenuControl if control.icons is None else IconButtonsControl
32
+ str: PromptControl if control.value_range is None else (DropdownMenuControl if control.icons is None else IconButtonsControl),
33
33
  }
34
34
 
35
35
  if control_type not in control_class_map:
@@ -90,15 +90,17 @@ class DropdownMenuControl(BaseControl):
90
90
  raise ValueError("Invalid control type")
91
91
 
92
92
  def create(self) -> gr.Dropdown:
93
- # Create a horizontal layout to hold the dropdown menu
94
93
  self.control_widget = gr.Dropdown(label=self.name, choices=self.ctrl.value_range, value=self.ctrl.value)
95
94
  return self.control_widget
96
95
 
97
- def reset(self):
98
- index = self.control_widget.findText(self.ctrl.value)
99
- if index >= 0:
100
- self.control_widget.setCurrentIndex(index)
101
- self.control_widget.setCurrentIndex(index)
96
+
97
+ class PromptControl(BaseControl):
98
+ def check_control_type(self):
99
+ assert self.ctrl._type == str
100
+
101
+ def create(self) -> gr.Text:
102
+ self.control_widget = gr.Text(label=self.name, value=self.ctrl.value)
103
+ return self.control_widget
102
104
 
103
105
 
104
106
  class IconButtonsControl(BaseControl):
@@ -1,4 +1,4 @@
1
- from matplotlib.widgets import Slider, CheckButtons, RadioButtons
1
+ from matplotlib.widgets import Slider, CheckButtons, RadioButtons, TextBox
2
2
  from interactive_pipe.headless.control import Control
3
3
  import logging
4
4
 
@@ -58,6 +58,7 @@ class BoolCheckButtonMatplotlibControl(BaseControl):
58
58
  class StringRadioButtonMatplotlibControl(BaseControl):
59
59
  def check_control_type(self):
60
60
  assert self.ctrl._type == str
61
+ assert self.ctrl.value_range is not None
61
62
 
62
63
  def create(self):
63
64
  options = self.ctrl.value_range
@@ -68,6 +69,26 @@ class StringRadioButtonMatplotlibControl(BaseControl):
68
69
  return radio
69
70
 
70
71
 
72
+
73
+ class PromptMatplotlibControl(BaseControl):
74
+ def check_control_type(self):
75
+ assert self.ctrl._type == str
76
+ assert self.ctrl.value_range is None
77
+
78
+ def create(self):
79
+ # Create a prompt for text input
80
+ self.text_box = TextBox(self.ax_control, 'Input', initial=self.ctrl.value)
81
+
82
+ # Function to handle the update when text is entered
83
+ def submit(text):
84
+ self.update_func(self.name, text)
85
+
86
+ # Connect the submission of the text box to the submit function
87
+ self.text_box.on_submit(submit)
88
+
89
+ return self.text_box
90
+
91
+
71
92
  class ControlFactory:
72
93
  @staticmethod
73
94
  def create_control(control: Control, update_func, ax_control=None):
@@ -77,7 +98,7 @@ class ControlFactory:
77
98
  bool: BoolCheckButtonMatplotlibControl,
78
99
  int: IntSliderMatplotlibControl,
79
100
  float: FloatSliderMatplotlibControl,
80
- str: StringRadioButtonMatplotlibControl,
101
+ str: PromptMatplotlibControl if control.value_range is None else StringRadioButtonMatplotlibControl,
81
102
  }
82
103
 
83
104
  if control_type not in control_class_map:
@@ -147,7 +147,7 @@ class MainWindow(MatplotlibWindow):
147
147
  self.main_gui.bind_keyboard_slider(
148
148
  ctrl, self.key_update_parameter)
149
149
  continue
150
- if ctrl._type == bool or ctrl._type == str:
150
+ if ctrl._type == bool or (ctrl._type == str and ctrl.value_range is not None):
151
151
  x_start = 0.01
152
152
  width = 0.08
153
153
  number_of_items = (1 if ctrl._type ==
@@ -155,10 +155,12 @@ class MainWindow(MatplotlibWindow):
155
155
  height = 0.02 * number_of_items
156
156
  y_start = self.next_slider_position - height
157
157
  self.next_slider_position -= self.spacer + height
158
- elif ctrl._type == float or ctrl._type == int:
158
+ elif ctrl._type == float or ctrl._type == int or (ctrl._type == str and ctrl.value_range is None):
159
159
  x_start = 0.25
160
160
  width = 0.65
161
161
  height = 0.02
162
+ if ctrl._type == str:
163
+ height = 0.05
162
164
  y_start = self.next_button_position - height
163
165
  self.next_button_position -= self.spacer + height
164
166
  if not dry_run:
@@ -30,6 +30,7 @@ if not PYQTVERSION:
30
30
  except ImportError:
31
31
  logging.warning("Cannot import PySide")
32
32
 
33
+
33
34
  class BaseControl(QWidget):
34
35
  def __init__(self, name, ctrl: Control, update_func, silent=False):
35
36
  super().__init__()
@@ -58,7 +59,8 @@ class ControlFactory:
58
59
  bool: TickBoxControl,
59
60
  int: IntSliderControl,
60
61
  float: FloatSliderControl,
61
- str: DropdownMenuControl if control.icons is None else IconButtonsControl
62
+ str: PromptControl if control.value_range is None else (
63
+ DropdownMenuControl if control.icons is None else IconButtonsControl)
62
64
  }
63
65
 
64
66
  if control_type not in control_class_map:
@@ -96,7 +98,7 @@ class IntSliderControl(BaseControl):
96
98
  else:
97
99
  slider_class = QSlider
98
100
  slider = slider_class(Qt.Orientation.Horizontal, self)
99
-
101
+
100
102
  slider.setRange(self.ctrl.value_range[0], self.ctrl.value_range[1])
101
103
  slider.setValue(self.ctrl.value_default)
102
104
  slider.setSingleStep(1)
@@ -222,6 +224,39 @@ class DropdownMenuControl(BaseControl):
222
224
  self.control_widget.setCurrentIndex(index)
223
225
 
224
226
 
227
+ class PromptControl(BaseControl):
228
+ def check_control_type(self):
229
+ assert self.ctrl._type == str
230
+ assert self.ctrl.value_range is None
231
+
232
+ def create(self):
233
+ # Create a horizontal layout to hold the text prompt
234
+ hbox = QHBoxLayout()
235
+
236
+ # Create the line edit (text input field)
237
+ self.control_widget = QLineEdit(self)
238
+
239
+ # Set the initial value of the text field if it's provided
240
+ if self.ctrl.value:
241
+ self.control_widget.setText(self.ctrl.value)
242
+
243
+ # Connect the textChanged signal to the update function if needed
244
+ self.control_widget.textChanged.connect(partial(self.update_func, self.name))
245
+
246
+ # Add the text input field to the horizontal layout
247
+ hbox.addWidget(self.control_widget)
248
+
249
+ # Add a label to the layout
250
+ label = QLabel(self.name, self)
251
+ hbox.addWidget(label)
252
+
253
+ return hbox
254
+
255
+ def reset(self):
256
+ # Reset the text field to the initial value
257
+ self.control_widget.setText(self.ctrl.value)
258
+
259
+
225
260
  class TickBoxControl(BaseControl):
226
261
  def check_control_type(self):
227
262
  assert self.ctrl._type == bool
@@ -387,7 +387,10 @@ class MainWindow(QWidget, InteractivePipeWindow):
387
387
  def update_parameter(self, idx, value):
388
388
  """Required implementation for graphical controllers update"""
389
389
  if self.ctrl[idx]._type == str:
390
- self.ctrl[idx].update(self.ctrl[idx].value_range[value])
390
+ if self.ctrl[idx].value_range is None:
391
+ self.ctrl[idx].update(value)
392
+ else:
393
+ self.ctrl[idx].update(self.ctrl[idx].value_range[value])
391
394
  elif self.ctrl[idx]._type == bool:
392
395
  self.ctrl[idx].update(bool(value))
393
396
  elif self.ctrl[idx]._type == float:
@@ -51,15 +51,19 @@ class Control():
51
51
  assert value_default >= value_range[0] and value_default <= value_range[1]
52
52
  elif isinstance(value_default, str):
53
53
  # similar to an enum
54
- assert value_range
55
- assert isinstance(value_range, list) or isinstance(
56
- value_range, tuple)
57
- for choice in value_range:
58
- assert isinstance(choice, str)
59
- assert value_default in value_range, f"{value_default} shall be in {value_range}"
60
- self._type = str
61
- if self.step is None:
62
- step = 1
54
+ if value_range is None:
55
+ logging.debug("string prompt only - no range")
56
+ self._type = str
57
+ else:
58
+ assert value_range
59
+ assert isinstance(value_range, list) or isinstance(
60
+ value_range, tuple)
61
+ for choice in value_range:
62
+ assert isinstance(choice, str)
63
+ assert value_default in value_range, f"{value_default} shall be in {value_range}"
64
+ self._type = str
65
+ if self.step is None:
66
+ step = 1
63
67
  else:
64
68
  raise TypeError("Wrong value type")
65
69
  self.value_range = value_range
@@ -94,7 +98,7 @@ class Control():
94
98
  assert isinstance(value, self._type), f"{type(value)} != {self._type}"
95
99
  if isinstance(value, float) or isinstance(value, int) and self.value_range:
96
100
  return max(self.value_range[0], min(value, self.value_range[1]))
97
- elif self._type == str:
101
+ elif self._type == str and self.value_range is not None:
98
102
  assert value in self.value_range, f"{value} shall be in {self.value_range}"
99
103
  return value
100
104
  else:
@@ -150,10 +154,19 @@ class CircularControl(Control):
150
154
  Replace a slider by a circular slider
151
155
  """
152
156
 
153
- def __init__(self, value_default: Union[int, float, bool, str], value_range: List[Union[int, float, str]] = None, modulo=True, name=None, step=None, filter_to_connect: Optional[FilterCore] = None, parameter_name_to_connect: Optional[str] = None) -> None:
157
+ def __init__(self, value_default: Union[int, float], value_range: List[Union[int, float]] = None, modulo=True, name=None, step=None, filter_to_connect: Optional[FilterCore] = None, parameter_name_to_connect: Optional[str] = None) -> None:
154
158
  super().__init__(value_default=value_default, value_range=value_range, name=name, step=step,
155
159
  filter_to_connect=filter_to_connect, parameter_name_to_connect=parameter_name_to_connect, icons=None)
156
160
  self.modulo = modulo
157
161
 
158
162
  def __repr__(self) -> str:
159
163
  return super().__repr__() + f"| modulo:{self.modulo}"
164
+
165
+
166
+ class TextPrompt(Control):
167
+ def __init__(self, value_default: str, name=None, filter_to_connect: Optional[FilterCore] = None, parameter_name_to_connect: Optional[str] = None) -> None:
168
+ super().__init__(value_default=value_default, value_range=None, name=name, step=None,
169
+ filter_to_connect=filter_to_connect, parameter_name_to_connect=parameter_name_to_connect, icons=None)
170
+
171
+ def __repr__(self) -> str:
172
+ return super().__repr__()
@@ -126,11 +126,14 @@ def control_from_tuple(short_params: Tuple, param_name: str = None) -> Union[Con
126
126
  assert len(
127
127
  short_params) >= 2, f"providing a value range is mandatory like (min, max) or (min, max, step)"
128
128
  value_range = short_params[start]
129
- assert isinstance(value_range, list) or isinstance(
130
- value_range, tuple), f"value range should be a tuple or a list, provided {value_range}"
131
- if (isinstance(value_default, float) or isinstance(value_default, int)) and len(value_range) >= 3:
132
- step = value_range[2]
133
- value_range = value_range[:2]
129
+ if value_range is None:
130
+ pass
131
+ else:
132
+ assert isinstance(value_range, list) or isinstance(
133
+ value_range, tuple), f"value range should be a tuple or a list, provided {value_range}"
134
+ if (isinstance(value_default, float) or isinstance(value_default, int)) and len(value_range) >= 3:
135
+ step = value_range[2]
136
+ value_range = value_range[:2]
134
137
  else:
135
138
  # ["cat", "dog", "tree"] -> default value = "cat"
136
139
  # [-10, 10, 1] -> default val = average(-10, 10), step=1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: interactive_pipe
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
5
5
  Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
@@ -106,7 +106,7 @@ pip install -e ".[full]"
106
106
 
107
107
  ## :scroll: Features
108
108
 
109
- **Version 0.8.3**
109
+ **Version 0.8.4**
110
110
  - Modular multi-image processing filters
111
111
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
112
112
  - Support in jupyter notebooks
@@ -117,6 +117,7 @@ pip install -e ".[full]"
117
117
  - :new: gradio backend (+allows sharing with others).
118
118
  - :new: Audio support in Gradio (live audio or display several players by returning 1D numpy arrays)
119
119
  - :new: Circular sliders for Qt Backend
120
+ - :new: Text prompt (`free_text=("Hello world!", None),`)
120
121
 
121
122
 
122
123