Skip to content
Open
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
4 changes: 4 additions & 0 deletions daras_ai_v2/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,10 @@ def get_run_title(cls, sr: SavedRun, pr: PublishedRun | None) -> str:
def get_recipe_title(cls) -> str:
return cls.get_root_pr().title or cls.title or cls.workflow.label

@classmethod
def get_recipe_short_title(cls) -> str:
return f"{cls.workflow.emoji} {cls.workflow.short_title}"

Comment on lines +1143 to +1146
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix call vs. attribute for emoji/short_title to avoid bound-method strings in UI

bots.models.workflow exposes emoji()/short_title() as methods (no @property shown). Using them as attributes renders bound-method text. Call them or handle both styles.

 @classmethod
 def get_recipe_short_title(cls) -> str:
-    return f"{cls.workflow.emoji} {cls.workflow.short_title}"
+    # Support both method and property styles on Workflow
+    emoji = cls.workflow.emoji() if callable(getattr(cls.workflow, "emoji", None)) else cls.workflow.emoji
+    short = cls.workflow.short_title() if callable(getattr(cls.workflow, "short_title", None)) else cls.workflow.short_title
+    return f"{emoji} {short}".strip()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@classmethod
def get_recipe_short_title(cls) -> str:
return f"{cls.workflow.emoji} {cls.workflow.short_title}"
@classmethod
def get_recipe_short_title(cls) -> str:
# Support both method and property styles on Workflow
emoji = cls.workflow.emoji() if callable(getattr(cls.workflow, "emoji", None)) else cls.workflow.emoji
short = cls.workflow.short_title() if callable(getattr(cls.workflow, "short_title", None)) else cls.workflow.short_title
return f"{emoji} {short}".strip()
🤖 Prompt for AI Agents
daras_ai_v2/base.py around lines 1143-1146: cls.workflow.emoji and
cls.workflow.short_title are methods on the workflow model, but the code treats
them as attributes which yields bound-method strings in the UI; change the
implementation to call them when callable (e.g., emoji = cls.workflow.emoji() if
callable(getattr(cls.workflow, "emoji", None)) else cls.workflow.emoji) and
similarly for short_title, with safe fallbacks (empty string or str(...)) before
constructing and returning the formatted title.

def get_explore_image(self) -> str:
meta = self.workflow.get_or_create_metadata()
img = meta.default_image or self.explore_image or ""
Expand Down
4 changes: 2 additions & 2 deletions daras_ai_v2/workflow_url_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ def edit_done_button(key: str):

def edit_button(key: str):
gui.button(
'<i class="fa-regular fa-pencil text-warning"></i>',
'<i class="fa-regular fa-pencil text-black"></i>',
key=key + ":edit-mode",
type="tertiary",
)


def del_button(key: str):
gui.button(
'<i class="fa-regular fa-trash text-danger"></i>',
'<i class="fa-regular fa-trash text-black"></i>',
key=key,
type="tertiary",
)
Expand Down
163 changes: 112 additions & 51 deletions recipes/BulkRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,65 +412,126 @@ def render_description(self):
"""
)

def render_run_url_inputs(self, key: str, del_key: str, d: dict):
from daras_ai_v2.all_pages import all_home_pages
def _render_url_input_only(self, key: str, del_key: str, d: dict, is_mobile: bool):
columns = [8, 4] if is_mobile else [9, 3]
col1, col2 = gui.columns(
columns, responsive=False, style={"--bs-gutter-x": "0.25rem"}
)

init_workflow_selector(d, key)
with col1:
url = gui.text_input(
"",
key=key,
value=d.get("url"),
placeholder="https://gooey.ai/.../?run_id=...",
)

col1, col2, col3, col4 = gui.columns([9, 1, 1, 1], responsive=False)
if not d.get("workflow") and d.get("url"):
with col1:
url = gui.text_input(
"",
key=key,
value=d.get("url"),
placeholder="https://gooey.ai/.../?run_id=...",
)
with col2:
with col2:
with gui.div(className="d-flex justify-content-between"):
edit_done_button(key)
else:
with col1:
scol1, scol2 = gui.columns([1, 1], responsive=False)
gui.url_button(url)
del_button(del_key)

return url

def _render_workflow_selector(self, key: str, d: dict):
from daras_ai_v2.all_pages import all_home_pages

options = {
page_cls.workflow: page_cls.get_recipe_short_title()
for page_cls in all_home_pages
}
last_workflow_key = "__last_run_url_workflow"
workflow = gui.selectbox(
"",
key=key + ":workflow",
value=(d.get("workflow") or gui.session_state.get(last_workflow_key)),
options=options,
format_func=lambda x: options[x],
)
d["workflow"] = workflow
# use this to set default for next time
gui.session_state[last_workflow_key] = workflow
return workflow

def _render_url_selector(self, key: str, d: dict, workflow):
page_cls = Workflow(workflow).page_cls
url_options = get_published_run_options(
page_cls, current_user=self.request.user
)
url_options.update(d.get("--added_workflows", {}))

url = gui.selectbox(
"",
key=key,
options=url_options,
value=d.get("url"),
format_func=lambda x: url_options[x],
)
return url

def _render_workflow_mode_mobile(self, key: str, del_key: str, d: dict):
wcol1, wcol2 = gui.columns(
[8, 4], responsive=False, style={"--bs-gutter-x": "0.25rem"}
)

with wcol1:
with gui.div(className="pt-1"):
workflow = self._render_workflow_selector(key, d)

with wcol2:
with gui.div(className="d-flex justify-content-between"):
edit_button(key)
gui.url_button(d.get("url", ""))
del_button(del_key)

with gui.div(className="pb-2"):
url = self._render_url_selector(key, d, workflow)

return url

def _render_workflow_mode_desktop(self, key: str, del_key: str, d: dict):
col1, col2 = gui.columns(
[9, 3], responsive=False, style={"--bs-gutter-x": "0.25rem"}
)

with col1:
scol1, scol2 = gui.columns(
[3, 9], responsive=False, style={"--bs-gutter-x": "0.5rem"}
)

with scol1:
with gui.div(className="pt-1"):
options = {
page_cls.workflow: page_cls.get_recipe_title()
for page_cls in all_home_pages
}
last_workflow_key = "__last_run_url_workflow"
workflow = gui.selectbox(
"",
key=key + ":workflow",
value=(
d.get("workflow")
or gui.session_state.get(last_workflow_key)
),
options=options,
format_func=lambda x: options[x],
)
d["workflow"] = workflow
# use this to set default for next time
gui.session_state[last_workflow_key] = workflow
workflow = self._render_workflow_selector(key, d)

with scol2:
page_cls = Workflow(workflow).page_cls
options = get_published_run_options(
page_cls, current_user=self.request.user
)
options.update(d.get("--added_workflows", {}))
with gui.div(className="pt-1"):
url = gui.selectbox(
"",
key=key,
options=options,
value=d.get("url"),
format_func=lambda x: options[x],
)
with col2:
url = self._render_url_selector(key, d, workflow)

with col2:
with gui.div(className="d-flex justify-content-between"):
edit_button(key)
with col3:
gui.url_button(url)
with col4:
del_button(del_key)
gui.url_button(url)
del_button(del_key)

return url

def render_run_url_inputs(self, key: str, del_key: str, d: dict):
init_workflow_selector(d, key)

if not d.get("workflow") and d.get("url"):
with gui.div(className="d-block d-lg-none"):
url = self._render_url_input_only(key, del_key, d, is_mobile=True)

with gui.div(className="d-none d-lg-block"):
url = self._render_url_input_only(key, del_key, d, is_mobile=False)

else:
with gui.div(className="d-block d-lg-none"):
url = self._render_workflow_mode_mobile(key, del_key, d)

with gui.div(className="d-none d-lg-block"):
url = self._render_workflow_mode_desktop(key, del_key, d)

try:
url_to_runs(url)
Expand Down
Loading