DuoChat Codelab Part 2: Building the basic UI¶
In this section, we'll create the main layout for our DuoChat application, including the header, chat input area, and some basic styling. We'll use Mesop's components and styling system to create an attractive and functional UI.
Updating the Main Layout¶
Let's start by updating our main.py
file to include a more structured layout. We'll use Mesop's box
component for layout and add some custom styles.
Replace the content of main.py
with the following:
import mesop as me
ROOT_BOX_STYLE = me.Style(
background="#e7f2ff",
height="100%",
font_family="Inter",
display="flex",
flex_direction="column",
)
@me.page(
path="/",
stylesheets=[
"https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
],
)
def page():
with me.box(style=ROOT_BOX_STYLE):
header()
with me.box(
style=me.Style(
width="min(680px, 100%)",
margin=me.Margin.symmetric(
horizontal="auto",
vertical=36,
),
)
):
me.text(
"Chat with multiple models at once",
style=me.Style(
font_size=20,
margin=me.Margin(bottom=24),
),
)
chat_input()
def header():
with me.box(
style=me.Style(
padding=me.Padding.all(16),
),
):
me.text(
"DuoChat",
style=me.Style(
font_weight=500,
font_size=24,
color="#3D3929",
letter_spacing="0.3px",
),
)
def chat_input():
with me.box(
style=me.Style(
border_radius=16,
padding=me.Padding.all(8),
background="white",
display="flex",
width="100%",
)
):
with me.box(style=me.Style(flex_grow=1)):
me.native_textarea(
placeholder="Enter a prompt",
style=me.Style(
padding=me.Padding(top=16, left=16),
outline="none",
width="100%",
border=me.Border.all(me.BorderSide(style="none")),
),
)
with me.content_button(type="icon"):
me.icon("send")
Run the Mesop app and look at the changes:
Let's review the changes:
- We've added a
ROOT_BOX_STYLE
to set the overall layout and background color. - We're importing a custom font (Inter) using the
stylesheets
parameter in the@me.page
decorator. - We've created separate functions for the
header
andchat_input
components. - The main layout uses nested
box
components with custom styles to create a centered, responsive design.
Understanding Mesop's Styling System¶
Mesop's styling system is based on Python classes that correspond to CSS properties. You can learn more by reading the Style API docs.
Adding Interactivity¶
Now, let's add some basic interactivity to our chat input. We'll update the chat_input
function to handle user input:
@me.stateclass
class State:
input: str = ""
def on_blur(e: me.InputBlurEvent):
state = me.state(State)
state.input = e.value
def chat_input():
state = me.state(State)
with me.box(
style=me.Style(
border_radius=16,
padding=me.Padding.all(8),
background="white",
display="flex",
width="100%",
)
):
with me.box(style=me.Style(flex_grow=1)):
me.native_textarea(
value=state.input,
placeholder="Enter a prompt",
on_blur=on_blur,
style=me.Style(
padding=me.Padding(top=16, left=16),
outline="none",
width="100%",
border=me.Border.all(me.BorderSide(style="none")),
),
)
with me.content_button(type="icon", on_click=send_prompt):
me.icon("send")
def send_prompt(e: me.ClickEvent):
state = me.state(State)
print(f"Sending prompt: {state.input}")
state.input = ""
Here's what we've added:
- A
State
class to manage the application state, including the user's input. - An
on_blur
function to update the state when the user switches focus from the textarea. - A
send_prompt
function that will be called when the send button is clicked.
Running the Updated Application¶
Run the application again with mesop main.py
and navigate to http://localhost:32123
. You should now see a styled header, a centered layout, and a functional chat input area.
Troubleshooting¶
If you're having trouble, compare your code to the solution.
Next Steps¶
In the next section, we'll dive deeper into state management and implement the model picker dialog.