Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

functions: ux clean-up #429

Merged
merged 6 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion daras_ai_v2/analysis_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
Expand Down
13 changes: 7 additions & 6 deletions daras_ai_v2/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -1478,15 +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()

with gui.expander("⚙️ Settings"):
if self.functions_in_settings:
functions_input(self.request.user)
self.render_settings()
if self.show_settings:
with gui.expander("⚙️ Settings"):
self.render_settings()
if self.functions_in_settings:
functions_input(self.request.user)

with placeholder:
self.render_variables()
Expand All @@ -1501,7 +1503,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()
Expand Down
2 changes: 1 addition & 1 deletion daras_ai_v2/bot_integration_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions daras_ai_v2/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
company = '<i class="fa-regular fa-buildings"></i>'
copy = '<i class="fa-solid fa-copy"></i>'
preview = '<i class="fa-solid fa-eye"></i>'
add = '<i class="fa-regular fa-add"></i>'

code = '<i class="fa-regular fa-code"></i>'
chat = '<i class="fa-regular fa-messages"></i>'
Expand Down
17 changes: 13 additions & 4 deletions daras_ai_v2/prompt_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,31 @@
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 <a href='https://jinja.palletsprojects.com/en/3.1.x/templates/' target='_blank'>Jinja</a>, e.g. `{{ my_variable }}`\n ",
key: str = "variables",
allow_add: bool = False,
):
from daras_ai_v2.workflow_url_input import del_button

def render_title_desc():
gui.write(label)
gui.caption(
f"{description} <a href='/variables-help' target='_blank'>Learn more</a>.",
unsafe_allow_html=True,
)

# find all variables in the prompts
env = jinja2.sandbox.SandboxedEnvironment()
template_var_names = set()
Expand Down Expand Up @@ -56,7 +65,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)
Expand Down Expand Up @@ -93,7 +102,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:
Expand All @@ -105,7 +114,7 @@ def variables_input(
)
with col2:
gui.button(
'<i class="fa-regular fa-add"></i> Add',
f"{icons.add} Add",
key=var_add_key,
type="tertiary",
)
Expand Down
20 changes: 13 additions & 7 deletions daras_ai_v2/workflow_url_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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(
Expand Down Expand Up @@ -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)
Expand All @@ -166,13 +170,15 @@ 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
}

return options
if include_root:
# include root recipe if requested
options_dict = {
page_cls.get_root_published_run().get_app_url(): "Default",
} | options_dict

return options_dict
18 changes: 18 additions & 0 deletions functions/migrations/0002_alter_calledfunction_trigger.py
Original file line number Diff line number Diff line change
@@ -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')]),
),
]
4 changes: 2 additions & 2 deletions functions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
14 changes: 11 additions & 3 deletions functions/recipe_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -133,20 +133,28 @@ 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"

if gui.checkbox(
f"##### {field_title_desc(BasePage.RequestModel, key)}",
key=f"--enable-{key}",
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. <a href='/functions-help' target='_blank'>Learn more.</a>",
unsafe_allow_html=True,
)
list_view_editor(
add_btn_label="➕ Add Function",
add_btn_label="Add Function",
add_btn_type="tertiary",
key=key,
render_inputs=render_function_input,
)
gui.write("---")
else:
gui.session_state.pop(key, None)

Expand Down
4 changes: 2 additions & 2 deletions recipes/BulkEval.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -261,7 +261,7 @@ def render_agg_inputs(key: str, del_key: str, d: AggFunction):
gui.html("<br>")
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,
)
Expand Down
12 changes: 8 additions & 4 deletions recipes/BulkRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -619,7 +620,8 @@ def read_df_any(f_url: str) -> "pd.DataFrame":

def list_view_editor(
*,
add_btn_label: str,
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],
Expand Down Expand Up @@ -658,5 +660,7 @@ 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:
with gui.center():
gui.button(f"{icons.add} {add_btn_label}", key=add_key, type=add_btn_type)
return new_lst
10 changes: 6 additions & 4 deletions recipes/CompareLLM.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
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
from daras_ai_v2.language_model import (
run_language_model,
LargeLanguageModels,
SUPERSCRIPT,
ResponseFormatType,
)
from daras_ai_v2.language_model_settings_widgets import (
language_model_settings,
Expand Down Expand Up @@ -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"
Expand Down
10 changes: 8 additions & 2 deletions recipes/Functions.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -83,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"):
Expand Down
2 changes: 1 addition & 1 deletion recipes/Translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading
Loading