Skip to content

Instantly share code, notes, and snippets.

@cpsievert
Created February 18, 2025 23:11
Show Gist options
  • Save cpsievert/8ab4b904beacda691e9a5bcba53074ac to your computer and use it in GitHub Desktop.
Save cpsievert/8ab4b904beacda691e9a5bcba53074ac to your computer and use it in GitHub Desktop.
A real example of py-shiny's MarkdownStream() + chatlas
from chatlas import ChatAnthropic
from faicons import icon_svg
from shiny import reactive
from shiny.express import input, render, ui
chat_model = ChatAnthropic(
system_prompt="""
You are a helpful AI fitness coach.
Give detailed workout plans to users based on their fitness goals and experience level.
Before getting into details, give a brief introduction to the workout plan.
Keep the overall tone encouraging and professional yet friendly.
Generate the response in Markdown format and avoid using h1, h2, or h3.
""",
)
ui.page_opts(title="Personalized Workout Plan Generator")
with ui.sidebar(open={"mobile": "always-above"}):
ui.input_select(
"goal",
"Fitness Goal",
["Strength", "Cardio", "Flexibility", "General Fitness"],
)
ui.input_selectize(
"equipment",
"Available Equipment",
["Dumbbells", "Barbell", "Resistance Bands", "Bodyweight"],
multiple=True,
selected=["Bodyweight", "Barbell"],
)
ui.input_slider("experience", "Experience Level", min=1, max=10, value=5)
ui.input_slider("duration", "Duration (mins)", min=15, max=90, step=5, value=45)
ui.input_select(
"daysPerWeek",
"Days per Week",
[str(i) for i in range(1, 8)],
selected="3",
)
ui.input_task_button("generate", "Get Workout", icon=icon_svg("person-running"))
@render.express
def download_ui():
if not workout_plan():
return
@render.download(filename="workout_plan.md", label="Download Workout")
def download():
yield workout_plan()
# Create a Markdown stream to display the workout plan
md_stream = ui.MarkdownStream("response_stream")
md_stream.ui(
content="""
Hi there! πŸ‘‹ I'm your AI fitness coach. πŸ’ͺ
Fill out the form in the sidebar to get started. πŸ“ πŸ‹οΈβ€β™‚ ️
""",
)
# When the user clicks the "Generate Workout" button, generate a workout plan
@reactive.effect
@reactive.event(input.generate)
async def _():
prompt = f"""
Generate a {input.duration()}-minute workout plan for a {input.goal()} fitness goal.
On a scale of 1-10, I have a level {input.experience()} experience,
works out {input.daysPerWeek()} days per week, and have access to:
{", ".join(input.equipment()) if input.equipment() else "no equipment"}.
Format the response in Markdown.
"""
stream = await md_stream.stream(await chat_model.stream_async(prompt))
current_stream.set(stream)
current_stream = reactive.value(None)
@reactive.calc
def workout_plan():
if not current_stream():
return None
stream = current_stream()
return stream.result()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment