From 3cc3c3badab2189911d8eacb83d894b4e1a7d789 Mon Sep 17 00:00:00 2001 From: anish-work Date: Tue, 13 Aug 2024 00:52:14 +0530 Subject: [PATCH 1/6] functions: ux clean-up --- daras_ai_v2/base.py | 6 +++--- daras_ai_v2/prompt_vars.py | 11 +++++++++-- .../0002_alter_calledfunction_trigger.py | 18 ++++++++++++++++++ functions/models.py | 4 ++-- functions/recipe_functions.py | 13 +++++++++++-- recipes/BulkRunner.py | 5 +++-- 6 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 functions/migrations/0002_alter_calledfunction_trigger.py diff --git a/daras_ai_v2/base.py b/daras_ai_v2/base.py index 8e3610a28..29afc5314 100644 --- a/daras_ai_v2/base.py +++ b/daras_ai_v2/base.py @@ -136,7 +136,7 @@ class BasePage: class RequestModel(BaseModel): functions: list[RecipeFunction] | None = Field( - title="🧩 Functions", + title="🧩 Developer Tools and Functions", ) variables: dict[str, typing.Any] = Field( None, @@ -1483,10 +1483,11 @@ def _render_input_col(self): self.render_form_v2() placeholder = gui.div() + gui.write("---") with gui.expander("⚙️ Settings"): + self.render_settings() if self.functions_in_settings: functions_input(self.request.user) - self.render_settings() with placeholder: self.render_variables() @@ -1501,7 +1502,6 @@ def _render_input_col(self): def render_variables(self): if not self.functions_in_settings: - gui.write("---") functions_input(self.request.user) variables_input( template_keys=self.template_keys, allow_add=is_functions_enabled() diff --git a/daras_ai_v2/prompt_vars.py b/daras_ai_v2/prompt_vars.py index 7a74c7116..dc0976f31 100644 --- a/daras_ai_v2/prompt_vars.py +++ b/daras_ai_v2/prompt_vars.py @@ -19,6 +19,13 @@ def variables_input( ): from daras_ai_v2.workflow_url_input import del_button + def render_title_desc(): + gui.write(label) + gui.caption( + "Variables let you pass custom parameters to your workflow. Access a variable in your instruction prompt with {{ }} eg. {{ my_variable }}. Learn more.", + unsafe_allow_html=True, + ) + # find all variables in the prompts env = jinja2.sandbox.SandboxedEnvironment() template_var_names = set() @@ -56,7 +63,7 @@ def variables_input( continue if not title_shown: - gui.write(label) + render_title_desc() title_shown = True col1, col2 = gui.columns([11, 1], responsive=False) @@ -93,7 +100,7 @@ def variables_input( if allow_add: if not title_shown: - gui.write(label) + render_title_desc() gui.newline() col1, col2, _ = gui.columns([6, 2, 4], responsive=False) with col1: diff --git a/functions/migrations/0002_alter_calledfunction_trigger.py b/functions/migrations/0002_alter_calledfunction_trigger.py new file mode 100644 index 000000000..a373cbc25 --- /dev/null +++ b/functions/migrations/0002_alter_calledfunction_trigger.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-08-12 12:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('functions', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='calledfunction', + name='trigger', + field=models.IntegerField(choices=[(1, 'Before'), (2, 'After')]), + ), + ] diff --git a/functions/models.py b/functions/models.py index 0901fb109..be1be7a5e 100644 --- a/functions/models.py +++ b/functions/models.py @@ -13,8 +13,8 @@ class _TriggerData(typing.NamedTuple): class FunctionTrigger(_TriggerData, GooeyEnum): - pre = _TriggerData(label="Pre", db_value=1) - post = _TriggerData(label="Post", db_value=2) + pre = _TriggerData(label="Before", db_value=1) + post = _TriggerData(label="After", db_value=2) class RecipeFunction(BaseModel): diff --git a/functions/recipe_functions.py b/functions/recipe_functions.py index b43ea16e6..ac0803f8f 100644 --- a/functions/recipe_functions.py +++ b/functions/recipe_functions.py @@ -117,7 +117,7 @@ def render_function_input(list_key: str, del_key: str, d: dict): from daras_ai_v2.workflow_url_input import workflow_url_input from recipes.Functions import FunctionsPage - col1, col2 = gui.columns([2, 10], responsive=False) + col1, col2 = gui.columns([3, 9], responsive=True) with col1: col1.node.props["className"] += " pt-1" d["trigger"] = enum_selector( @@ -134,6 +134,7 @@ def render_function_input(list_key: str, del_key: str, d: dict): del_key=del_key, current_user=current_user, ) + col2.node.children[0].props["className"] += " col-12" if gui.checkbox( f"##### {field_title_desc(BasePage.RequestModel, key)}", @@ -141,11 +142,19 @@ def render_function_input(list_key: str, del_key: str, d: dict): value=key in gui.session_state, ): gui.session_state.setdefault(key, [{}]) + with gui.div(className="d-flex align-items-center"): + gui.write("###### Functions") + gui.caption( + "Functions give your workflow the ability run Javascript code (with webcalls!) allowing it execute logic, use common JS libraries or make external API calls before or after the workflow runs. Learn more.", + unsafe_allow_html=True, + ) list_view_editor( - add_btn_label="➕ Add Function", + add_btn_label=None, key=key, render_inputs=render_function_input, ) + gui.button("➕ Add Function", key=f"--{key}:add", type="tertiary") + gui.write("---") else: gui.session_state.pop(key, None) diff --git a/recipes/BulkRunner.py b/recipes/BulkRunner.py index 2cbde30e0..ff7a9dfa3 100644 --- a/recipes/BulkRunner.py +++ b/recipes/BulkRunner.py @@ -619,7 +619,7 @@ def read_df_any(f_url: str) -> "pd.DataFrame": def list_view_editor( *, - add_btn_label: str, + add_btn_label: str = None, key: str, render_labels: typing.Callable = None, render_inputs: typing.Callable[[str, str, dict], None], @@ -658,5 +658,6 @@ def list_view_editor( with label_placeholder: render_labels() gui.session_state[key] = new_lst - gui.button(add_btn_label, key=add_key) + if add_btn_label: + gui.button(add_btn_label, key=add_key) return new_lst From 0b79de42fd174044b9f7e7ac67599712e8ad3ede Mon Sep 17 00:00:00 2001 From: anish-work Date: Tue, 13 Aug 2024 22:40:07 +0530 Subject: [PATCH 2/6] remove under line in settings --- daras_ai_v2/base.py | 2 +- functions/recipe_functions.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/daras_ai_v2/base.py b/daras_ai_v2/base.py index 29afc5314..667fe5a1c 100644 --- a/daras_ai_v2/base.py +++ b/daras_ai_v2/base.py @@ -1487,7 +1487,7 @@ def _render_input_col(self): with gui.expander("⚙️ Settings"): self.render_settings() if self.functions_in_settings: - functions_input(self.request.user) + functions_input(self.request.user, is_in_settings=True) with placeholder: self.render_variables() diff --git a/functions/recipe_functions.py b/functions/recipe_functions.py index ac0803f8f..f7138ca8d 100644 --- a/functions/recipe_functions.py +++ b/functions/recipe_functions.py @@ -109,7 +109,9 @@ def is_functions_enabled(key="functions") -> bool: return bool(gui.session_state.get(f"--enable-{key}")) -def functions_input(current_user: AppUser, key="functions"): +def functions_input( + current_user: AppUser, key="functions", is_in_settings: bool = False +): from recipes.BulkRunner import list_view_editor from daras_ai_v2.base import BasePage @@ -155,7 +157,8 @@ def render_function_input(list_key: str, del_key: str, d: dict): ) gui.button("➕ Add Function", key=f"--{key}:add", type="tertiary") - gui.write("---") + if not is_in_settings: + gui.write("---") else: gui.session_state.pop(key, None) From 40af15d7fe8d492c9d611188dd194ca254eeee7b Mon Sep 17 00:00:00 2001 From: anish-work Date: Tue, 13 Aug 2024 23:15:05 +0530 Subject: [PATCH 3/6] hide settings in /functions --- daras_ai_v2/base.py | 11 ++++++----- recipes/Functions.py | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/daras_ai_v2/base.py b/daras_ai_v2/base.py index 667fe5a1c..a375d774a 100644 --- a/daras_ai_v2/base.py +++ b/daras_ai_v2/base.py @@ -1478,16 +1478,17 @@ def update_flag_for_run(self, run_id: str, uid: str, is_flagged: bool): # Functions in every recipe feels like overkill for now, hide it in settings functions_in_settings = True + show_settings = True def _render_input_col(self): self.render_form_v2() placeholder = gui.div() - gui.write("---") - with gui.expander("⚙️ Settings"): - self.render_settings() - if self.functions_in_settings: - functions_input(self.request.user, is_in_settings=True) + if self.show_settings: + with gui.expander("⚙️ Settings"): + self.render_settings() + if self.functions_in_settings: + functions_input(self.request.user, is_in_settings=True) with placeholder: self.render_variables() diff --git a/recipes/Functions.py b/recipes/Functions.py index e376bc061..cebf4d5dd 100644 --- a/recipes/Functions.py +++ b/recipes/Functions.py @@ -21,6 +21,7 @@ class FunctionsPage(BasePage): title = "Functions" workflow = Workflow.FUNCTIONS slug_versions = ["functions", "tools", "function", "fn", "functions"] + show_settings = False class RequestModel(BaseModel): code: str = Field( @@ -85,6 +86,9 @@ def render_form_v2(self): def render_variables(self): variables_input(template_keys=["code"], allow_add=True) + def render_settings(self): + raise NotImplementedError + def render_output(self): if error := gui.session_state.get("error"): with gui.tag("pre", className="bg-danger bg-opacity-25"): From 4e7be3656a5d78b0be2ee50c85503b6007c2605c Mon Sep 17 00:00:00 2001 From: anish-work Date: Wed, 14 Aug 2024 02:17:49 +0530 Subject: [PATCH 4/6] remove default options from functions --- daras_ai_v2/workflow_url_input.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/daras_ai_v2/workflow_url_input.py b/daras_ai_v2/workflow_url_input.py index a37929378..30500bf68 100644 --- a/daras_ai_v2/workflow_url_input.py +++ b/daras_ai_v2/workflow_url_input.py @@ -166,13 +166,19 @@ def get_published_run_options( pr.updated_at, # newer first ), ) - - options = { - # root recipe - page_cls.get_root_published_run().get_app_url(): "Default", - } | { + options_dict = { pr.get_app_url(): get_title_breadcrumbs(page_cls, pr.saved_run, pr).h1_title for pr in saved_runs_and_examples } + options = ( + options_dict + if page_cls.workflow == Workflow.FUNCTIONS + else { + # root recipe + page_cls.get_root_published_run().get_app_url(): "Default", + } + | options_dict + ) + return options From 4637475b79477a4b0fcad21581d82c55ce52755b Mon Sep 17 00:00:00 2001 From: anish-work Date: Wed, 14 Aug 2024 02:23:40 +0530 Subject: [PATCH 5/6] remove render_settings from functions not needed --- recipes/Functions.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/recipes/Functions.py b/recipes/Functions.py index cebf4d5dd..129e39af3 100644 --- a/recipes/Functions.py +++ b/recipes/Functions.py @@ -86,9 +86,6 @@ def render_form_v2(self): def render_variables(self): variables_input(template_keys=["code"], allow_add=True) - def render_settings(self): - raise NotImplementedError - def render_output(self): if error := gui.session_state.get("error"): with gui.tag("pre", className="bg-danger bg-opacity-25"): From 0a6ae3b1c2ef22e93ed339255b270fb705288022 Mon Sep 17 00:00:00 2001 From: Dev Aggarwal Date: Wed, 14 Aug 2024 20:11:16 +0530 Subject: [PATCH 6/6] Standardize button labels and improve function UX - Remove emoji from "Add a Graph", "Add a Prompt", "Add an Eval", etc., button labels - Add new `add` icon in `icons.py` and use it for add buttons - Add `include_root` parameter to `workflow_url_input` and related functions - Improve `variables_input` UX with reusable description text - Refactor `list_view_editor` to center add button with type options - Update markdown for consistent capabilities sections visuals in CompareLLM and VideoBots --- daras_ai_v2/analysis_results.py | 2 +- daras_ai_v2/base.py | 2 +- daras_ai_v2/bot_integration_widgets.py | 2 +- daras_ai_v2/icons.py | 1 + daras_ai_v2/prompt_vars.py | 8 +++++--- daras_ai_v2/workflow_url_input.py | 20 ++++++++++---------- functions/recipe_functions.py | 12 ++++-------- recipes/BulkEval.py | 4 ++-- recipes/BulkRunner.py | 9 ++++++--- recipes/CompareLLM.py | 10 ++++++---- recipes/Functions.py | 9 +++++++-- recipes/Translation.py | 2 +- recipes/VideoBots.py | 7 +++---- 13 files changed, 48 insertions(+), 40 deletions(-) diff --git a/daras_ai_v2/analysis_results.py b/daras_ai_v2/analysis_results.py index 5bd519982..6e43e3585 100644 --- a/daras_ai_v2/analysis_results.py +++ b/daras_ai_v2/analysis_results.py @@ -69,7 +69,7 @@ def render_analysis_results_page( gui.session_state.setdefault("selected_graphs", graphs) selected_graphs = list_view_editor( - add_btn_label="➕ Add a Graph", + add_btn_label="Add a Graph", key="selected_graphs", render_inputs=partial(render_inputs, results), ) diff --git a/daras_ai_v2/base.py b/daras_ai_v2/base.py index a375d774a..e02808f61 100644 --- a/daras_ai_v2/base.py +++ b/daras_ai_v2/base.py @@ -1488,7 +1488,7 @@ def _render_input_col(self): with gui.expander("⚙️ Settings"): self.render_settings() if self.functions_in_settings: - functions_input(self.request.user, is_in_settings=True) + functions_input(self.request.user) with placeholder: self.render_variables() diff --git a/daras_ai_v2/bot_integration_widgets.py b/daras_ai_v2/bot_integration_widgets.py index 4958f389d..a1f36b859 100644 --- a/daras_ai_v2/bot_integration_widgets.py +++ b/daras_ai_v2/bot_integration_widgets.py @@ -94,7 +94,7 @@ def render_workflow_url_input(key: str, del_key: str | None, d: dict): input_analysis_runs.append(dict(saved_run=sr, published_run=None)) list_view_editor( - add_btn_label="➕ Add", + add_btn_label="Add", key="analysis_urls", render_inputs=render_workflow_url_input, flatten_dict_key="url", diff --git a/daras_ai_v2/icons.py b/daras_ai_v2/icons.py index 91150051a..c862da919 100644 --- a/daras_ai_v2/icons.py +++ b/daras_ai_v2/icons.py @@ -14,6 +14,7 @@ company = '' copy = '' preview = '' +add = '' code = '' chat = '' diff --git a/daras_ai_v2/prompt_vars.py b/daras_ai_v2/prompt_vars.py index dc0976f31..c315da996 100644 --- a/daras_ai_v2/prompt_vars.py +++ b/daras_ai_v2/prompt_vars.py @@ -3,17 +3,19 @@ from datetime import datetime from types import SimpleNamespace +import gooey_gui as gui import jinja2 import jinja2.meta import jinja2.sandbox -import gooey_gui as gui +from daras_ai_v2 import icons def variables_input( *, template_keys: typing.Iterable[str], label: str = "###### ⌥ Variables", + description: str = "Variables let you pass custom parameters to your workflow. Access a variable in your instruction prompt with Jinja, e.g. `{{ my_variable }}`\n ", key: str = "variables", allow_add: bool = False, ): @@ -22,7 +24,7 @@ def variables_input( def render_title_desc(): gui.write(label) gui.caption( - "Variables let you pass custom parameters to your workflow. Access a variable in your instruction prompt with {{ }} eg. {{ my_variable }}. Learn more.", + f"{description} Learn more.", unsafe_allow_html=True, ) @@ -112,7 +114,7 @@ def render_title_desc(): ) with col2: gui.button( - ' Add', + f"{icons.add} Add", key=var_add_key, type="tertiary", ) diff --git a/daras_ai_v2/workflow_url_input.py b/daras_ai_v2/workflow_url_input.py index 30500bf68..5c5f7b2e9 100644 --- a/daras_ai_v2/workflow_url_input.py +++ b/daras_ai_v2/workflow_url_input.py @@ -21,6 +21,7 @@ def workflow_url_input( del_key: str = None, current_user: AppUser | None = None, allow_none: bool = False, + include_root: bool = True ) -> tuple[typing.Type[BasePage], SavedRun, PublishedRun | None] | None: init_workflow_selector(internal_state, key) @@ -38,7 +39,9 @@ def workflow_url_input( else: internal_state["workflow"] = page_cls.workflow with col1: - options = get_published_run_options(page_cls, current_user=current_user) + options = get_published_run_options( + page_cls, current_user=current_user, include_root=include_root + ) options.update(internal_state.get("--added_workflows", {})) with gui.div(className="pt-1"): url = gui.selectbox( @@ -143,6 +146,7 @@ def url_to_runs( def get_published_run_options( page_cls: typing.Type[BasePage], current_user: AppUser | None = None, + include_root: bool = True, ) -> dict[str, str]: # approved examples pr_query = Q(is_approved_example=True, visibility=PublishedRunVisibility.PUBLIC) @@ -171,14 +175,10 @@ def get_published_run_options( for pr in saved_runs_and_examples } - options = ( - options_dict - if page_cls.workflow == Workflow.FUNCTIONS - else { - # root recipe + if include_root: + # include root recipe if requested + options_dict = { page_cls.get_root_published_run().get_app_url(): "Default", - } - | options_dict - ) + } | options_dict - return options + return options_dict diff --git a/functions/recipe_functions.py b/functions/recipe_functions.py index f7138ca8d..5d4c07b87 100644 --- a/functions/recipe_functions.py +++ b/functions/recipe_functions.py @@ -109,9 +109,7 @@ def is_functions_enabled(key="functions") -> bool: return bool(gui.session_state.get(f"--enable-{key}")) -def functions_input( - current_user: AppUser, key="functions", is_in_settings: bool = False -): +def functions_input(current_user: AppUser, key="functions"): from recipes.BulkRunner import list_view_editor from daras_ai_v2.base import BasePage @@ -135,6 +133,7 @@ def render_function_input(list_key: str, del_key: str, d: dict): internal_state=d, del_key=del_key, current_user=current_user, + include_root=False, ) col2.node.children[0].props["className"] += " col-12" @@ -151,14 +150,11 @@ def render_function_input(list_key: str, del_key: str, d: dict): unsafe_allow_html=True, ) list_view_editor( - add_btn_label=None, + add_btn_label="Add Function", + add_btn_type="tertiary", key=key, render_inputs=render_function_input, ) - gui.button("➕ Add Function", key=f"--{key}:add", type="tertiary") - - if not is_in_settings: - gui.write("---") else: gui.session_state.pop(key, None) diff --git a/recipes/BulkEval.py b/recipes/BulkEval.py index ce25e512d..7f92a53e1 100644 --- a/recipes/BulkEval.py +++ b/recipes/BulkEval.py @@ -239,7 +239,7 @@ def render_inputs(key: str, del_key: str, d: EvalPrompt): gui.write("##### " + field_title_desc(self.RequestModel, "eval_prompts")) list_view_editor( - add_btn_label="➕ Add a Prompt", + add_btn_label="Add a Prompt", key="eval_prompts", render_inputs=render_inputs, ) @@ -261,7 +261,7 @@ def render_agg_inputs(key: str, del_key: str, d: AggFunction): gui.html("
") gui.write("##### " + field_title_desc(self.RequestModel, "agg_functions")) list_view_editor( - add_btn_label="➕ Add an Aggregation", + add_btn_label="Add an Aggregation", key="agg_functions", render_inputs=render_agg_inputs, ) diff --git a/recipes/BulkRunner.py b/recipes/BulkRunner.py index ff7a9dfa3..f700effac 100644 --- a/recipes/BulkRunner.py +++ b/recipes/BulkRunner.py @@ -8,6 +8,7 @@ import gooey_gui as gui from bots.models import Workflow, SavedRun from daras_ai.image_input import upload_file_from_bytes +from daras_ai_v2 import icons from daras_ai_v2.base import BasePage from daras_ai_v2.breadcrumbs import get_title_breadcrumbs from daras_ai_v2.doc_search_settings_widgets import ( @@ -97,7 +98,7 @@ def preview_image(self, state: dict) -> str | None: def render_form_v2(self): gui.write(f"##### {field_title_desc(self.RequestModel, 'run_urls')}") run_urls = list_view_editor( - add_btn_label="➕ Add a Workflow", + add_btn_label="Add a Workflow", key="run_urls", render_inputs=self.render_run_url_inputs, flatten_dict_key="url", @@ -246,7 +247,7 @@ def render_form_v2(self): gui.write("---") gui.write(f"##### {field_title_desc(self.RequestModel, 'eval_urls')}") list_view_editor( - add_btn_label="➕ Add an Eval", + add_btn_label="Add an Eval", key="eval_urls", render_inputs=self.render_eval_url_inputs, flatten_dict_key="url", @@ -620,6 +621,7 @@ def read_df_any(f_url: str) -> "pd.DataFrame": def list_view_editor( *, add_btn_label: str = None, + add_btn_type: str = "secondary", key: str, render_labels: typing.Callable = None, render_inputs: typing.Callable[[str, str, dict], None], @@ -659,5 +661,6 @@ def list_view_editor( render_labels() gui.session_state[key] = new_lst if add_btn_label: - gui.button(add_btn_label, key=add_key) + with gui.center(): + gui.button(f"{icons.add} {add_btn_label}", key=add_key, type=add_btn_type) return new_lst diff --git a/recipes/CompareLLM.py b/recipes/CompareLLM.py index cc8c93313..513421146 100644 --- a/recipes/CompareLLM.py +++ b/recipes/CompareLLM.py @@ -2,9 +2,9 @@ import random import typing -from pydantic import BaseModel, Field - import gooey_gui as gui +from pydantic import BaseModel + from bots.models import Workflow from daras_ai_v2.base import BasePage from daras_ai_v2.enum_selector_widget import enum_multiselect @@ -12,7 +12,6 @@ run_language_model, LargeLanguageModels, SUPERSCRIPT, - ResponseFormatType, ) from daras_ai_v2.language_model_settings_widgets import ( language_model_settings, @@ -78,11 +77,14 @@ def render_form_v2(self): enum_multiselect( LargeLanguageModels, - label="#### 🤗 Compare Language Models", + label="#### 🧠 Language Models", key="selected_models", checkboxes=False, ) + gui.markdown("#### 💪 Capabilities") + # -- functions will render here in parent -- + def validate_form_v2(self): assert gui.session_state["input_prompt"], "Please enter a Prompt" assert gui.session_state["selected_models"], "Please select at least one model" diff --git a/recipes/Functions.py b/recipes/Functions.py index 129e39af3..179c13d95 100644 --- a/recipes/Functions.py +++ b/recipes/Functions.py @@ -1,9 +1,9 @@ import typing +import gooey_gui as gui import requests from pydantic import BaseModel, Field -import gooey_gui as gui from bots.models import Workflow from daras_ai_v2 import settings from daras_ai_v2.base import BasePage @@ -84,7 +84,12 @@ def render_form_v2(self): ) def render_variables(self): - variables_input(template_keys=["code"], allow_add=True) + variables_input( + template_keys=["code"], + allow_add=True, + description="Pass custom parameters to your function and access the parent workflow data. " + "Variables will be passed down as the first argument to your anonymous JS function.", + ) def render_output(self): if error := gui.session_state.get("error"): diff --git a/recipes/Translation.py b/recipes/Translation.py index dada4cf2a..b8061beb2 100644 --- a/recipes/Translation.py +++ b/recipes/Translation.py @@ -90,7 +90,7 @@ def related_workflows(self) -> list: def render_form_v2(self): gui.write("###### Source Texts") list_view_editor( - add_btn_label="➕ Add Text", + add_btn_label="Add Text", key="texts", render_inputs=render_text_input, flatten_dict_key="text", diff --git a/recipes/VideoBots.py b/recipes/VideoBots.py index 46ce36ef5..37fd094bb 100644 --- a/recipes/VideoBots.py +++ b/recipes/VideoBots.py @@ -343,7 +343,7 @@ def render_form_v2(self): accept=["audio/*", "application/*", "video/*", "text/*"], ) - gui.markdown("#### Capabilities") + gui.markdown("#### 💪 Capabilities") if gui.checkbox( "##### 🗣️ Text to Speech & Lipsync", value=bool(gui.session_state.get("tts_provider")), @@ -425,9 +425,7 @@ def render_form_v2(self): if gui.checkbox( "##### 🩻 Photo & Document Intelligence", - value=bool( - gui.session_state.get("document_model"), - ), + value=bool(gui.session_state.get("document_model")), ): if settings.AZURE_FORM_RECOGNIZER_KEY: doc_model_descriptions = azure_form_recognizer_models() @@ -439,6 +437,7 @@ def render_form_v2(self): options=doc_model_descriptions, format_func=lambda x: f"{doc_model_descriptions[x]} ({x})", ) + gui.write("---") else: gui.session_state["document_model"] = None