Abid Ali Awan
Add auth links to setup dialog
8e3b244
from __future__ import annotations
import reflex as rx
from .report_formatting import MARKDOWN_CSS
from .state import State
PAGE_BG = "linear-gradient(135deg, #fbfdff 0%, #fffdf7 48%, #f8fff9 100%)"
PAGE_PADDING = {"initial": "1rem", "sm": "1.25rem", "lg": "2rem"}
PANEL_PADDING = {"initial": "1rem", "sm": "1.25rem"}
GUIDE_URL = "https://machinelearningmastery.com/how-to-build-a-multi-agent-research-assistant-in-python/"
OPENAI_API_KEYS_URL = "https://platform.openai.com/api-keys"
OLOSTEP_AUTH_URL = "https://olostep.com/auth"
def status_badge() -> rx.Component:
return rx.badge(
State.status,
color_scheme=rx.cond(
State.status == "Complete",
"green",
rx.cond(State.status == "Failed", "red", "blue"),
),
variant="soft",
size="2",
)
def log_panel() -> rx.Component:
return rx.box(
rx.hstack(
rx.hstack(
rx.icon("activity", size=18, color="#0b7285"),
rx.heading("Working", size="3", color="#14323b"),
align="center",
spacing="2",
),
status_badge(),
justify="between",
align="center",
width="100%",
),
rx.vstack(
rx.foreach(
State.logs,
lambda item: rx.text(
item,
font_family="monospace",
font_size="0.8rem",
color="#263238",
),
),
align="stretch",
spacing="2",
margin_top="0.6rem",
),
max_height="10rem",
overflow_y="auto",
padding="0.85rem",
border="1px solid #b6e3ea",
border_radius="8px",
background="rgba(235, 251, 255, 0.9)",
box_shadow="0 8px 24px rgba(8, 92, 115, 0.10)",
width="100%",
)
def report_panel() -> rx.Component:
return rx.box(
rx.hstack(
rx.spacer(),
rx.button(
rx.icon("download", size=17),
"Download PDF",
on_click=State.download_pdf,
background="#2f9e44",
color="white",
border_radius="8px",
padding_x="1rem",
padding_y="0.45rem",
cursor="pointer",
margin_top="1rem",
margin_right="1rem",
_hover={
"background": "#238b36",
"transform": "translateY(-1px)",
"box_shadow": "0 4px 12px rgba(47, 158, 68, 0.35)",
},
transition="all 0.2s ease",
),
justify="end",
align="start",
width="100%",
),
rx.html(
MARKDOWN_CSS
+ '<div class="md-report" style="padding: 0.5rem 1.25rem 1rem;">'
+ State.report_html
+ "</div>",
width="100%",
overflow_x="auto",
),
padding=PANEL_PADDING,
border="1px solid #dde6ec",
border_radius="8px",
background="rgba(255, 255, 255, 0.96)",
box_shadow="0 16px 40px rgba(36, 48, 58, 0.10)",
width="100%",
overflow_x="auto",
)
def search_bar() -> rx.Component:
return rx.hstack(
rx.input(
value=State.query,
on_change=State.set_query,
on_key_down=State.handle_key_down,
placeholder="Ask anything",
height="2.8rem",
width="100%",
flex="1 1 auto",
min_width="0",
background="transparent",
border="0",
box_shadow="none",
font_size="1.05rem",
margin_left="1.5rem",
padding_left="0",
text_indent="0.85rem",
padding_right={"initial": "0.75rem", "sm": "1rem"},
),
rx.button(
rx.icon("rotate_ccw", size=19),
on_click=State.clear_all,
aria_label="Reset",
height="3.15rem",
width="3.15rem",
min_width="3.15rem",
padding="0",
flex="0 0 auto",
border_radius="8px",
background="transparent",
color="#111111",
box_shadow="none",
cursor="pointer",
_hover={"background": "#f3f4f6"},
),
rx.cond(
State.is_running,
rx.button(
rx.icon("square", size=16),
on_click=State.stop_report,
aria_label="Stop",
height="3.15rem",
width="3.15rem",
min_width="3.15rem",
padding="0",
flex="0 0 auto",
border_radius="999px",
background="#111111",
color="white",
cursor="pointer",
position="relative",
z_index="1",
margin_right="1rem",
),
rx.button(
rx.icon("search", size=17),
on_click=State.run_report,
aria_label="Search",
height="3.15rem",
width="3.15rem",
min_width="3.15rem",
padding="0",
flex="0 0 auto",
border_radius="999px",
background="#111111",
color="white",
cursor="pointer",
position="relative",
z_index="1",
margin_right="1rem",
),
),
width="100%",
min_height="5rem",
align="center",
justify="between",
spacing={"initial": "3", "sm": "4"},
align_self="center",
padding={
"initial": "0.75rem 1.85rem 0.75rem 1.2rem",
"sm": "0.8rem 2.35rem 0.8rem 1.6rem",
},
border="1px solid #d8d8d8",
border_radius="999px",
background="rgba(255, 255, 255, 0.96)",
box_shadow="0 18px 55px rgba(16, 24, 40, 0.12)",
)
def prompt_suggestions() -> rx.Component:
return rx.hstack(
rx.button(
"Is remote work dying in 2026?",
on_click=State.set_query("Is remote work dying in 2026?"),
variant="soft",
color_scheme="gray",
border_radius="999px",
),
rx.button(
"What's behind the global coffee shortage?",
on_click=State.set_query("What's behind the global coffee shortage?"),
variant="soft",
color_scheme="gray",
border_radius="999px",
),
rx.button(
"Are electric cars actually cheaper to own?",
on_click=State.set_query("Are electric cars actually cheaper to own?"),
variant="soft",
color_scheme="gray",
border_radius="999px",
),
justify="center",
align="center",
wrap="wrap",
spacing="3",
width="100%",
)
def page_header() -> rx.Component:
return rx.vstack(
rx.heading(
"What do you want to research today?",
size={"initial": "6", "md": "7"},
weight="regular",
color="#101828",
text_align="center",
line_height="1.15",
),
rx.hstack(
rx.badge("Manager", color_scheme="blue", variant="soft", size="2", border_radius="999px"),
rx.badge("Judge", color_scheme="orange", variant="soft", size="2", border_radius="999px"),
rx.badge("Researcher", color_scheme="purple", variant="soft", size="2", border_radius="999px"),
rx.badge("Analyst", color_scheme="green", variant="soft", size="2", border_radius="999px"),
justify="center",
align="center",
wrap="wrap",
spacing="2",
),
width="100%",
align="center",
spacing="3",
)
def result_area() -> rx.Component:
return rx.cond(
State.is_running,
log_panel(),
rx.cond(
State.report_markdown != "",
report_panel(),
rx.box(
rx.text("Enter a question and press Search.", color="#52616b", align="center"),
padding="0.25rem",
width="100%",
),
),
)
def setup_dialog() -> rx.Component:
return rx.dialog.root(
rx.dialog.content(
rx.vstack(
rx.hstack(
rx.box(
rx.icon("key_round", size=22, color="#0b7285"),
display="flex",
align_items="center",
justify_content="center",
width="2.75rem",
height="2.75rem",
border_radius="8px",
background="#e7f7fa",
flex="0 0 auto",
),
rx.vstack(
rx.dialog.title(
"Add your own API keys",
color="#101828",
font_size="1.25rem",
line_height="1.2",
margin="0",
),
rx.dialog.description(
"This Space cannot run research until it has your OpenAI and Olostep keys.",
color="#52616b",
line_height="1.5",
margin="0",
),
align="stretch",
spacing="1",
),
align="start",
spacing="3",
width="100%",
),
rx.box(
rx.text("Missing environment variables", color="#475467", size="2"),
rx.text(
State.missing_env_text,
color="#101828",
font_family="monospace",
font_size="0.9rem",
margin_top="0.25rem",
),
padding="0.85rem",
border="1px solid #dde6ec",
border_radius="8px",
background="#f8fafc",
width="100%",
),
rx.vstack(
rx.hstack(rx.icon("copy", size=16), rx.text("Duplicate this app."), align="center", spacing="2"),
rx.hstack(rx.icon("settings", size=16), rx.text("Open Settings > Variables and secrets."), align="center", spacing="2"),
rx.hstack(
rx.icon("plus", size=16),
rx.text("Add OPENAI_API_KEY and OLOSTEP_API_KEY, then restart the app."),
align="center",
spacing="2",
),
align="stretch",
spacing="2",
color="#344054",
font_size="0.95rem",
width="100%",
),
rx.hstack(
rx.link(
rx.icon("book_open", size=16),
"Full guide",
href=GUIDE_URL,
is_external=True,
color="#0b7285",
display="flex",
align_items="center",
gap="0.45rem",
font_weight="600",
),
rx.link(
rx.icon("key_round", size=16),
"OpenAI keys",
href=OPENAI_API_KEYS_URL,
is_external=True,
color="#0b7285",
display="flex",
align_items="center",
gap="0.45rem",
font_weight="600",
),
rx.link(
rx.icon("lock_keyhole", size=16),
"Olostep auth",
href=OLOSTEP_AUTH_URL,
is_external=True,
color="#0b7285",
display="flex",
align_items="center",
gap="0.45rem",
font_weight="600",
),
rx.spacer(),
rx.button(
"Close",
on_click=State.close_setup_dialog,
background="#111111",
color="white",
border_radius="8px",
padding_x="1rem",
cursor="pointer",
),
width="100%",
align="center",
wrap="wrap",
spacing="3",
),
align="stretch",
spacing="4",
),
max_width="30rem",
padding="1.25rem",
border_radius="8px",
box_shadow="0 24px 70px rgba(16, 24, 40, 0.24)",
),
open=State.show_setup_dialog,
on_open_change=State.set_setup_dialog_open,
)
def index() -> rx.Component:
return rx.box(
setup_dialog(),
rx.vstack(
page_header(),
search_bar(),
prompt_suggestions(),
rx.cond(
State.error != "",
rx.callout(State.error, icon="triangle_alert", color_scheme="red", width="100%"),
),
result_area(),
spacing="5",
align="stretch",
padding=PANEL_PADDING,
width="100%",
max_width="780px",
margin_x="auto",
),
width="100%",
max_width="100vw",
padding=PAGE_PADDING,
min_height="100vh",
background=PAGE_BG,
overflow_x="hidden",
display="flex",
align_items="center",
justify_content="center",
)
app = rx.App()
app.add_page(index, route="/", title="Multi-Agent Research Assistant")