Skip to content
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
179 changes: 111 additions & 68 deletions daras_ai_v2/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
render_create_workspace_alert,
set_current_workspace,
)
from routers.root import PREVIEW_ROUTE_WORKFLOWS


MAX_SEED = 4294967294
gooey_rng = Random()
Expand Down Expand Up @@ -390,29 +392,17 @@ def render(self):

header_placeholder = gui.div(className="my-3 w-100")
with (
gui.styled(
"""
@media (max-width: 768px) {
& button {
font-size: 0.9rem;
padding: 0.3rem !important
}
}
& .nav-item {
font-size: smaller;
font-weight: bold;
}
& button {
padding: 0.4rem !important;
}
"""
),
gui.div(className="position-relative"),
gui.styled(NAV_TABS_CSS),
gui.div(className="position-relative", id="recipe-nav-tabs"),
gui.nav_tabs(),
):
for tab in self.get_tabs():
url = self.current_app_url(tab)
with gui.nav_item(url, active=tab == self.tab):
if tab == RecipeTabs.run and self.tab == RecipeTabs.preview:
force_active_lg = gui.tag("span", className="active-lg")
else:
force_active_lg = gui.dummy()
with force_active_lg, gui.nav_item(url, active=tab == self.tab):
gui.html(tab.title)

self._render_saved_generated_timestamp()
Expand All @@ -432,7 +422,7 @@ def _render_header(self):
can_save = self.can_user_save_run(sr, pr)
request_changed = self._has_request_changed()

if self.tab != RecipeTabs.run:
if self.tab != RecipeTabs.run and self.tab != RecipeTabs.preview:
# Examples, API, Saved, etc
if self.tab == RecipeTabs.saved or self.tab == RecipeTabs.history:
with gui.div(className="mb-2"):
Expand Down Expand Up @@ -609,7 +599,7 @@ def render_social_buttons(self):
):
publish_dialog_ref = gui.use_alert_dialog(key="publish-modal")

if self.tab == RecipeTabs.run:
if self.tab == RecipeTabs.run or self.tab == RecipeTabs.preview:
if self.current_pr.is_root():
render_help_button(self.workflow)
if self.is_logged_in():
Expand Down Expand Up @@ -1173,7 +1163,7 @@ def get_tabs(self):

def render_selected_tab(self):
match self.tab:
case RecipeTabs.run:
case RecipeTabs.run | RecipeTabs.preview:
if self.current_sr.retention_policy == RetentionPolicy.delete:
self.render_deleted_output()
return
Expand Down Expand Up @@ -1201,10 +1191,8 @@ def render_selected_tab(self):
),
)

with gui.styled(OUTPUT_TABS_CSS):
output_col, input_col = gui.tabs(
[f"{icons.preview} Preview", f"{icons.edit} Edit"]
)
with gui.styled(INPUT_OUTPUT_COLS_CSS):
input_col, output_col = gui.columns([3, 2], gap="medium")
with input_col:
submitted = self._render_input_col()
with output_col:
Expand Down Expand Up @@ -1762,25 +1750,30 @@ def _render_report_button(self):
show_settings = True

def _render_input_col(self):
self.render_form_v2()
placeholder = gui.div()

if self.show_settings:
with gui.div(className="bg-white"):
with gui.expander("⚙️ Settings"):
self.render_settings()
if self.functions_in_settings:
functions_input(self.request.user)
if self.tab == RecipeTabs.preview:
hide_on_mobile = "d-none d-lg-block"
else:
hide_on_mobile = ""
with gui.div(className=hide_on_mobile):
self.render_form_v2()
placeholder = gui.div()

if self.show_settings:
with gui.div(className="bg-white"):
with gui.expander("⚙️ Settings"):
self.render_settings()
if self.functions_in_settings:
functions_input(self.request.user)

with placeholder:
self.render_variables()
with placeholder:
self.render_variables()

submitted = self.render_submit_button()
with gui.div(style={"textAlign": "right", "fontSize": "smaller"}):
terms_caption = self.get_terms_caption()
gui.caption(f"_{terms_caption}_")
submitted = self.render_submit_button()
with gui.div(style={"textAlign": "right", "fontSize": "smaller"}):
terms_caption = self.get_terms_caption()
gui.caption(f"_{terms_caption}_")

return submitted
return submitted

def get_terms_caption(self):
return "With each run, you agree to Gooey.AI's [terms](https://gooey.ai/terms) & [privacy policy](https://gooey.ai/privacy)."
Expand Down Expand Up @@ -1832,7 +1825,13 @@ def _render_output_col(self, *, submitted: bool = False, is_deleted: bool = Fals
if submitted:
self.submit_and_redirect()

with gui.div(style=dict(position="sticky", top="0.5rem")):
if self.tab == RecipeTabs.run and self.workflow in PREVIEW_ROUTE_WORKFLOWS:
hide_on_mobile = "d-none d-lg-block pb-2"
else:
hide_on_mobile = ""
with gui.div(
style=dict(position="sticky", top="0.5rem"), className=hide_on_mobile
):
run_state = self.get_run_state(gui.session_state)
if run_state == RecipeRunState.failed:
self._render_failed_output()
Expand Down Expand Up @@ -1905,7 +1904,11 @@ def submit_and_redirect(
sr = self.on_submit(unsaved_state=unsaved_state)
if not sr:
return
raise gui.RedirectException(self.app_url(run_id=sr.run_id, uid=sr.uid))
if self.workflow in PREVIEW_ROUTE_WORKFLOWS:
tab = RecipeTabs.preview
else:
tab = None
raise gui.RedirectException(self.app_url(run_id=sr.run_id, uid=sr.uid, tab=tab))

def publish_and_redirect(self) -> typing.NoReturn | None:
assert self.is_logged_in()
Expand Down Expand Up @@ -2555,36 +2558,76 @@ class TitleValidationError(Exception):
pass


OUTPUT_TABS_CSS = """
& [data-reach-tab-list] {
text-align: center; margin-top: 0
INPUT_OUTPUT_COLS_CSS = """
& {
margin: -1rem 0 1rem 0;
padding-top: 1rem;
}

/* reset col padding in mobile */
& > div {
padding: 0;
}

@media (min-width: 768px) {
& [data-reach-tab-list] {
display: none;
}
& [data-reach-tab-panels] {
display: flex;
flex-direction: row-reverse;
width: 100%;
& {
background-color: #f9f9f9;
padding: 10px;
margin-top: -1rem;
}
& [data-reach-tab-panels] > div:nth-child(2) {
flex: 0 1 auto;
width: 60%;
max-width: 100%;
padding-right: 0.75rem;
/* set col padding in mobile */
& > div {
padding-left: calc(var(--bs-gutter-x) * .5);
padding-right: calc(var(--bs-gutter-x) * .5);
}
& [data-reach-tab-panels] > div:nth-child(1) {
flex: 0 0 auto;
width: 40%;
max-width: 100%;
padding-left: 0.75rem;
}
"""

NAV_TABS_CSS = """
@media (max-width: 768px) {
& button {
font-size: 0.9rem;
padding: 0.3rem !important
}
}
& .nav-item {
font-size: smaller;
font-weight: bold;
}
& button {
padding: 0.4rem !important;
}

& a:has(span.mobile-only-recipe-tab) {
display: block !important;
}

& li.nav-item:first-of-type button {
margin-left: 0 !important;
}

& ul.nav-tabs {
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
flex-wrap: nowrap !important;
display: flex;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
gap: 0.5rem;
}

@media (min-width: 768px) {
& a:has(span.mobile-only-recipe-tab) {
display: none !important;
}

/* RUN as active tab in lg view for preview route */
& span.active-lg button {
color: #000;
border-bottom: 2px solid black;
}
& [data-reach-tab-panel][hidden] {
display: block !important;

& ul.nav-tabs {
gap: 0;
}
}
"""
40 changes: 21 additions & 19 deletions daras_ai_v2/meta_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,25 +215,27 @@ def robots_tag_for_page(
is_root = pr and pr.saved_run == sr and pr.is_root()
is_example = pr and pr.saved_run == sr and not pr.is_root()

if not page.is_user_authorized(None):
# nofollow & noindex if page is not open for anonymous users
no_follow, no_index = True, True
else:
match page.tab:
case RecipeTabs.run if is_root or is_example:
no_follow, no_index = False, False
case RecipeTabs.run: # ordinary run (not example)
no_follow, no_index = False, True
case RecipeTabs.examples:
no_follow, no_index = False, False
case RecipeTabs.run_as_api:
no_follow, no_index = False, True
case RecipeTabs.integrations:
no_follow, no_index = True, True
case RecipeTabs.history:
no_follow, no_index = True, True
case RecipeTabs.saved:
no_follow, no_index = True, True
match page.tab:
case RecipeTabs.run if is_root or is_example:
no_follow, no_index = False, False
case RecipeTabs.preview if is_root or is_example:
no_follow, no_index = False, False
case RecipeTabs.run: # ordinary run (not example)
no_follow, no_index = False, True
case RecipeTabs.preview:
no_follow, no_index = False, True
case RecipeTabs.examples:
no_follow, no_index = False, False
case RecipeTabs.run_as_api:
no_follow, no_index = False, True
case RecipeTabs.integrations:
no_follow, no_index = True, True
case RecipeTabs.history:
no_follow, no_index = True, True
case RecipeTabs.saved:
no_follow, no_index = True, True
case _:
raise ValueError(f"Unknown tab: {page.tab}")

parts = []
if no_follow:
Expand Down
7 changes: 4 additions & 3 deletions recipes/VideoBots.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,12 +704,12 @@ def render_run_preview_output(self, state: dict):
scroll_into_view = False

def _render_running_output(self):
## The embedded web widget includes a running output, so just scroll it into view
## The embedded web widget includes a running output, so just scroll it into view to tabs which just above the widget

# language=JavaScript
gui.js(
"""
let elem = document.querySelector("#gooey-embed");
let elem = document.querySelector("#recipe-nav-tabs");
if (!elem) return;
if (elem.scrollIntoViewIfNeeded) {
elem.scrollIntoViewIfNeeded(false);
Expand Down Expand Up @@ -1546,11 +1546,12 @@ def lipsync_step(self, request, response):
response.output_video.append(lip_state["output_video"])

def render_header_extra(self):
if self.tab == RecipeTabs.run:
if self.tab == RecipeTabs.run or self.tab == RecipeTabs.preview:
render_demo_buttons_header(self.current_pr)

def get_tabs(self):
tabs = super().get_tabs()
tabs.insert(1, RecipeTabs.preview)
tabs.extend([RecipeTabs.integrations])
return tabs

Expand Down
24 changes: 22 additions & 2 deletions routers/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,18 @@ def chat_lib_route(request: Request, integration_id: str, integration_name: str
)


@gui.route(
app,
"/{page_slug}/preview/",
"/{page_slug}/{run_slug}/preview/",
"/{page_slug}/{run_slug}-{example_id}/preview/",
)
def preview_route(
request: Request, page_slug: str, run_slug: str = None, example_id: str = None
):
return render_recipe_page(request, page_slug, RecipeTabs.preview, example_id)


@gui.route(
app,
"/{path:path}",
Expand Down Expand Up @@ -876,9 +888,17 @@ class TabData(typing.NamedTuple):
route: typing.Callable


PREVIEW_ROUTE_WORKFLOWS = [Workflow.VIDEO_BOTS]


class RecipeTabs(TabData, Enum):
preview = TabData(
title=f"<span class='mobile-only-recipe-tab'>{icons.preview} Preview</span>",
label="",
route=preview_route,
)
run = TabData(
title=f"{icons.run} <span class='d-none d-lg-inline'>Run</span>",
title=f"{icons.run} Run",
label="",
route=recipe_or_handle_or_static,
)
Expand All @@ -898,7 +918,7 @@ class RecipeTabs(TabData, Enum):
route=history_route,
)
integrations = TabData(
title=f'<img width="20" height="20" style="margin-right: 4px;margin-top: -3px" src="{icons.integrations_img}" alt="Facebook, Whatsapp, Slack, Instagram Icons"> <span class="d-none d-lg-inline">Integrations</span>',
title=f'<img width="20" height="20" style="margin-right: 4px;margin-top: -3px" src="{icons.integrations_img}" alt="Facebook, Whatsapp, Slack, Instagram Icons"> Integrations',
label="Integrations",
route=integrations_route,
)
Expand Down