Skip to content

Commit

Permalink
Add some goldens for writing chat UIs (#919)
Browse files Browse the repository at this point in the history
* Add some goldens for writing chat UIs

- Add simple chat example
- Add fancy chat example
- Add other examples for enhancing simple chat
  • Loading branch information
richard-to authored Sep 2, 2024
1 parent d22087d commit a7c7a77
Show file tree
Hide file tree
Showing 37 changed files with 5,658 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<<<<<<< ORIGINAL
# Fancy header
with me.box(
style=me.Style(
background=me.theme_var("primary"),
padding=me.Padding.all(16),
border_radius=8,
margin=me.Margin(bottom=20),
display="flex",
align_items="center",
)
):
me.icon(
"chat", style=me.Style(color=me.theme_var("on-primary"), font_size=24)
)
me.text(
"AI Chatbot",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=24,
font_weight="bold",
margin=me.Margin(left=12),
),
)
me.text(
"Talk to our intelligent assistant",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=16,
margin=me.Margin(left=12),
),
)
=======
# Fancy header
with me.box(
style=me.Style(
background=me.theme_var("primary"),
padding=me.Padding.all(16),
border_radius=8,
margin=me.Margin(bottom=20),
display="flex",
justify_content="space-between",
)
):
with me.box(style=me.Style(display="flex", align_items="center")):
me.icon(
"chat", style=me.Style(color=me.theme_var("on-primary"), font_size=24)
)
me.text(
"AI Chatbot",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=24,
font_weight="bold",
margin=me.Margin(left=12),
flex_grow=1,
),
)
me.text(
"Talk to our intelligent assistant",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=16,
margin=me.Margin(left=12),
),
)
with me.content_button(type="icon"):
me.icon("dark_mode", style=me.Style(color=me.theme_var("on-primary")))
>>>>>>> UPDATED
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
import random
import time
from dataclasses import dataclass
from typing import Literal

import mesop as me

Role = Literal["user", "bot"]


@dataclass(kw_only=True)
class ChatMessage:
"""Chat message metadata."""

role: Role = "user"
content: str = ""
edited: bool = False


@me.stateclass
class State:
input: str
output: list[ChatMessage]
in_progress: bool


@me.page(path="/ai")
def page():
state = me.state(State)
with me.box(
style=me.Style(
color=me.theme_var("on-surface"),
background=me.theme_var("surface-container-lowest"),
display="flex",
flex_direction="column",
height="100%",
padding=me.Padding.all(15),
)
):
# Fancy header
with me.box(
style=me.Style(
background=me.theme_var("primary"),
padding=me.Padding.all(16),
border_radius=8,
margin=me.Margin(bottom=20),
display="flex",
justify_content="space-between",
)
):
with me.box(style=me.Style(display="flex", align_items="center")):
me.icon(
"chat", style=me.Style(color=me.theme_var("on-primary"), font_size=24)
)
me.text(
"AI Chatbot",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=24,
font_weight="bold",
margin=me.Margin(left=12),
flex_grow=1,
),
)
me.text(
"Talk to our intelligent assistant",
style=me.Style(
color=me.theme_var("on-primary"),
font_size=16,
margin=me.Margin(left=12),
),
)
with me.content_button(type="icon"):
me.icon("dark_mode", style=me.Style(color=me.theme_var("on-primary")))
# This contains the chat messages that have been recorded. This takes 50fr.
# This section can be replaced with other types of chat messages.

# We set overflow to scroll so that the chat input will be fixed at the bottom.
with me.box(style=me.Style(overflow_y="scroll", flex_grow=1)):
for msg in state.output:
# User chat message
if msg.role == "user":
with me.box(
style=me.Style(display="flex", gap=15, margin=me.Margin.all(20))
):
# User avatar/icon box
me.text(
"U",
style=me.Style(
background=me.theme_var("primary"),
border_radius="50%",
color=me.theme_var("on-primary"),
font_size=20,
height=40,
width=40,
text_align="center",
line_height="1",
padding=me.Padding(top=10),
margin=me.Margin(top=16),
),
)
# User query
me.markdown(msg.content)
else:
# Bot chat message
with me.box(
style=me.Style(display="flex", gap=15, margin=me.Margin.all(20))
):
# Bot avatar/icon box
me.text(
"B",
style=me.Style(
background=me.theme_var("secondary"),
border_radius="50%",
color=me.theme_var("on-secondary"),
font_size=20,
height=40,
width="40px",
text_align="center",
line_height="1",
padding=me.Padding(top=10),
margin=me.Margin(top=16),
),
)
# Bot message response
me.markdown(
msg.content,
style=me.Style(color=me.theme_var("on-surface")),
)
with me.box(
style=me.Style(
display="flex",
gap=10,
margin=me.Margin(top=8),
)
):
with me.content_button(
type="icon",
style=me.Style(
background=me.theme_var("surface-container-low"),
),
):
me.icon("thumb_up")
with me.content_button(
type="icon",
style=me.Style(
background=me.theme_var("surface-container-low"),
),
):
me.icon("thumb_down")
with me.content_button(
type="icon",
style=me.Style(
background=me.theme_var("surface-container-low"),
),
):
me.icon("refresh")

# This is for the basic chat input. This is the second row at 1fr.
# This section can be replaced with other types of chat inputs.
with me.box(
style=me.Style(
border_radius=16,
padding=me.Padding.all(8),
background=me.theme_var("surface-container-low"),
display="flex",
width="100%",
)
):
with me.box(
style=me.Style(
flex_grow=1,
)
):
me.native_textarea(
key="chat_input",
value=state.input,
on_blur=on_chat_input,
autosize=True,
min_rows=4,
placeholder="Enter your prompt",
style=me.Style(
color=me.theme_var("on-surface-variant"),
padding=me.Padding(top=16, left=16),
background=me.theme_var("surface-container-low"),
outline="none",
width="100%",
overflow_y="auto",
border=me.Border.all(
me.BorderSide(style="none"),
),
),
)
with me.content_button(
type="icon",
on_click=on_click_submit_chat_msg,
# If we're processing a message prevent new queries from being sent
disabled=state.in_progress,
):
me.icon("send")


def on_chat_input(e: me.InputBlurEvent):
"""Capture chat text input on blur."""
state = me.state(State)
state.input = e.value


def on_click_submit_chat_msg(e: me.ClickEvent):
"""Handles submitting a chat message."""
state = me.state(State)
if state.in_progress or not state.input:
return
input = state.input
# Clear the text input.
state.input = ""
yield

output = state.output
if output is None:
output = []
output.append(ChatMessage(role="user", content=input))
state.in_progress = True
yield

start_time = time.time()
# Send user input and chat history to get the bot response.
output_message = respond_to_chat(input, state.output)
assistant_message = ChatMessage(role="bot")
output.append(assistant_message)
state.output = output
for content in output_message:
assistant_message.content += content
# TODO: 0.25 is an abitrary choice. In the future, consider making this adjustable.
if (time.time() - start_time) >= 0.25:
start_time = time.time()
yield

state.in_progress = False
me.focus_component(key="chat_input")
yield


def respond_to_chat(input: str, history: list[ChatMessage]):
"""Displays random canned text.
Edit this function to process messages with a real chatbot/LLM.
"""
lines = [
"Mesop is a Python-based UI framework designed to simplify web UI development for engineers without frontend experience.",
"It leverages the power of the Angular web framework and Angular Material components, allowing rapid construction of web demos and internal tools.",
"With Mesop, developers can enjoy a fast build-edit-refresh loop thanks to its hot reload feature, making UI tweaks and component integration seamless.",
"Deployment is straightforward, utilizing standard HTTP technologies.",
"Mesop's component library aims for comprehensive Angular Material component coverage, enhancing UI flexibility and composability.",
"It supports custom components for specific use cases, ensuring developers can extend its capabilities to fit their unique requirements.",
"Mesop's roadmap includes expanding its component library and simplifying the onboarding processs.",
]
for line in random.sample(lines, random.randint(3, len(lines) - 1)):
yield line + " "
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add dark mode icon on the right end of the header
Loading

0 comments on commit a7c7a77

Please sign in to comment.