Skip to content

Instantly share code, notes, and snippets.

@mtanco
Last active July 12, 2022 22:53
Show Gist options
  • Save mtanco/9a5d0a1d951a9e3c877786de85866afd to your computer and use it in GitHub Desktop.
Save mtanco/9a5d0a1d951a9e3c877786de85866afd to your computer and use it in GitHub Desktop.
Display fake-streamed text data using H2O Wave. Pause and resume the real-time updates.
"""
Demo of Updating App Data in one card of an app
"""
from random import randint
from h2o_wave import Q, app, handle_on, main, on, ui
@app("/")
async def serve(q: Q):
# First time a browser comes to the app
if not q.client.initialized:
await initialize_client(q)
# User navigating
if q.args.tabs_nav == "live_update":
await live_update(q)
elif q.args.tabs_nav == "other_page":
await other_page(q)
# Handle other user interactions
await handle_on(q)
# Save to screen
await q.page.save()
async def initialize_client(q: Q) -> None:
"""
This happens the first time this browser tab comes to this app
"""
if not q.app.initialized:
# streamed text is the same for all users - use q.client or q.user to change the level of state
q.app.text = []
q.app.initialized = True
q.client.cards = []
q.client.stream_data = False
q.page["meta"] = ui.meta_card(
box="",
title="Streaming | H2O Wave",
layouts=[
ui.layout(
breakpoint="xs",
min_height="100vh",
max_width="1200px",
zones=[
ui.zone("header"),
ui.zone("title"),
ui.zone("content", size="1"),
ui.zone(name="footer"),
],
)
],
)
q.page["header"] = ui.header_card(
box="header",
title="My Wave App",
subtitle="Example to get us started",
image="https://cloud-internal.h2o.ai/logo.svg",
items=[
ui.tabs(
name="tabs_nav",
items=[
ui.tab(name="live_update", label="Live Update"),
ui.tab(name="other_page", label="Other Page"),
],
)
],
)
q.page["footer"] = ui.footer_card(
box="footer", caption="Made with 💛 using [H2O Wave](https://wave.h2o.ai)."
)
# Show the user the live updating page and begin streaming data
await live_update(q)
q.client.initialized = True
async def live_update(q: Q):
"""
This page has two buttons to start and stop live updating and a card for holding updated content
"""
clear_cards(q)
button_menu = ui.section_card(
box="title",
title="",
subtitle="",
items=[
ui.buttons(
items=[
ui.button(
name="start_stream",
label="Start Stream",
icon="Play",
primary=True,
disabled=q.client.stream_data,
),
ui.button(
name="pause_stream",
label="Pause Stream",
icon="Pause",
primary=True,
disabled=not q.client.stream_data,
),
],
justify="end",
)
],
)
add_card(q, "button_control", button_menu)
streamed_text = ui.form_card(
box=ui.box("content", height="500px"),
items=[ui.text("<br />".join(q.app.text))],
)
add_card(q, "streamed_text", streamed_text)
async def other_page(q: Q):
"""
This is some other app functionality
If you want the streamed data calls to keep happening do nothing special
If you want them to stop when the user is away from the updating page / card use: await pause_stream(q)
"""
# await pause_stream(q) # Optional depending on your use case!!!
clear_cards(q)
demo_card = ui.form_card(box="content", items=[ui.text("Some other app stuff")])
add_card(q, "demo_card", demo_card)
@on()
async def start_stream(q) -> None:
"""
User has clicked the "Start Stream" button
Every 2 seconds we update the content of a specific card
The user can still interact with other parts of the application
"""
q.client.stream_data = True # Variable so the rest of the app knows that this card is being streamed to
# Change information about our control buttons
q.page["button_control"].items[0].buttons.items[0].button.disabled = True
q.page["button_control"].items[0].buttons.items[1].button.disabled = False
# This will run until the variable is change somewhere else in the app code by a user interaction
while q.client.stream_data:
q.app.text.insert(0, create_text_data()) # Add new text to the top of the list
q.page["streamed_text"].items[0].text.content = "<br />".join(q.app.text)
await q.page.save()
await q.sleep(2)
@on()
async def pause_stream(q):
"""
User has clicked the "Pause Stream" button
Set the update variable to stop so that it no longer updates
"""
q.client.stream_data = False
q.page["button_control"].items[0].buttons.items[0].button.disabled = False
q.page["button_control"].items[0].buttons.items[1].button.disabled = True
# Use for cards that should be deleted on calling `clear_cards`. Useful for routing and page updates.
def add_card(q, name, card) -> None:
q.client.cards.append(name)
q.page[name] = card
def clear_cards(q) -> None:
for name in q.client.cards.copy():
del q.page[name]
q.client.cards = []
def create_text_data():
names = ["We", "I", "They", "He", "She", "Jack", "Jim"]
verbs = ["was", "is", "are", "were"]
nouns = ["playing a game", "watching television", "talking", "dancing", "speaking"]
sentence = (
names[randint(0, len(names) - 1)]
+ " "
+ verbs[randint(0, len(verbs) - 1)]
+ " "
+ nouns[randint(0, len(nouns) - 1)]
+ "."
)
return sentence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment