Skip to content

Commit b47ea60

Browse files
authored
Create starter kit template (google#631)
1 parent 1d629c7 commit b47ea60

File tree

5 files changed

+218
-0
lines changed

5 files changed

+218
-0
lines changed

mesop/examples/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ py_library(
4444
"//mesop/examples/docs",
4545
"//mesop/examples/integrations",
4646
"//mesop/examples/shared",
47+
"//mesop/examples/starter_kit",
4748
"//mesop/examples/testing",
4849
],
4950
)

mesop/examples/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from mesop.examples import playground_critic as playground_critic
2828
from mesop.examples import readme_app as readme_app
2929
from mesop.examples import scroll_into_view as scroll_into_view
30+
from mesop.examples import starter_kit as starter_kit
3031
from mesop.examples import sxs as sxs
3132
from mesop.examples import testing as testing
3233
from mesop.examples import viewport_size as viewport_size

mesop/examples/starter_kit/BUILD

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
load("//build_defs:defaults.bzl", "py_library")
2+
3+
package(
4+
default_visibility = ["//build_defs:mesop_examples"],
5+
)
6+
7+
py_library(
8+
name = "starter_kit",
9+
srcs = glob(["*.py"]),
10+
)
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from mesop.examples.starter_kit import (
2+
starter_kit as starter_kit,
3+
)
+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import time
2+
3+
import mesop as me
4+
5+
6+
@me.stateclass
7+
class State:
8+
input: str
9+
output: str
10+
in_progress: bool
11+
12+
13+
@me.page(path="/starter_kit")
14+
def page():
15+
with me.box(
16+
style=me.Style(
17+
background="#fff",
18+
min_height="calc(100% - 48px)",
19+
padding=me.Padding(bottom=16),
20+
)
21+
):
22+
with me.box(
23+
style=me.Style(
24+
width="min(720px, 100%)",
25+
margin=me.Margin.symmetric(horizontal="auto"),
26+
padding=me.Padding.symmetric(
27+
horizontal=16,
28+
),
29+
)
30+
):
31+
header_text()
32+
example_row()
33+
chat_input()
34+
output()
35+
footer()
36+
37+
38+
def header_text():
39+
with me.box(
40+
style=me.Style(
41+
padding=me.Padding(
42+
top=64,
43+
bottom=36,
44+
),
45+
)
46+
):
47+
me.text(
48+
"Mesop Starter Kit",
49+
style=me.Style(
50+
font_size=36,
51+
font_weight=700,
52+
background="linear-gradient(90deg, #4285F4, #AA5CDB, #DB4437) text",
53+
color="transparent",
54+
),
55+
)
56+
57+
58+
EXAMPLES = [
59+
"How to tie a shoe",
60+
"Make a brownie recipe",
61+
"Write an email asking for a sick day off",
62+
]
63+
64+
65+
def example_row():
66+
is_mobile = me.viewport_size().width < 640
67+
with me.box(
68+
style=me.Style(
69+
display="flex",
70+
flex_direction="column" if is_mobile else "row",
71+
gap=24,
72+
margin=me.Margin(bottom=36),
73+
)
74+
):
75+
for example in EXAMPLES:
76+
example_box(example, is_mobile)
77+
78+
79+
def example_box(example: str, is_mobile: bool):
80+
with me.box(
81+
style=me.Style(
82+
width="100%" if is_mobile else 200,
83+
height=140,
84+
background="#F0F4F9",
85+
padding=me.Padding.all(16),
86+
font_weight=500,
87+
line_height="1.5",
88+
border_radius=16,
89+
cursor="pointer",
90+
),
91+
key=example,
92+
on_click=click_example_box,
93+
):
94+
me.text(example)
95+
96+
97+
def click_example_box(e: me.ClickEvent):
98+
state = me.state(State)
99+
state.input = e.key
100+
101+
102+
def chat_input():
103+
state = me.state(State)
104+
with me.box(
105+
style=me.Style(
106+
padding=me.Padding.all(8),
107+
background="white",
108+
display="flex",
109+
width="100%",
110+
border=me.Border.all(
111+
me.BorderSide(width=0, style="solid", color="black")
112+
),
113+
border_radius=12,
114+
box_shadow="0 10px 20px #0000000a, 0 2px 6px #0000000a, 0 0 1px #0000000a",
115+
)
116+
):
117+
with me.box(
118+
style=me.Style(
119+
flex_grow=1,
120+
)
121+
):
122+
me.native_textarea(
123+
value=state.input,
124+
autosize=True,
125+
min_rows=4,
126+
placeholder="Enter your prompt",
127+
style=me.Style(
128+
padding=me.Padding(top=16, left=16),
129+
background="white",
130+
outline="none",
131+
width="100%",
132+
overflow_y="auto",
133+
border=me.Border.all(
134+
me.BorderSide(style="none"),
135+
),
136+
),
137+
on_blur=textarea_on_blur,
138+
)
139+
with me.content_button(type="icon", on_click=click_send):
140+
me.icon("send")
141+
142+
143+
def textarea_on_blur(e: me.InputBlurEvent):
144+
state = me.state(State)
145+
state.input = e.value
146+
147+
148+
def click_send(e: me.ClickEvent):
149+
state = me.state(State)
150+
if not state.input:
151+
return
152+
state.in_progress = True
153+
input = state.input
154+
state.input = ""
155+
yield
156+
157+
for chunk in call_api(input):
158+
state.output += chunk
159+
yield
160+
state.in_progress = False
161+
yield
162+
163+
164+
def call_api(input):
165+
# Replace this with an actual API call
166+
time.sleep(0.5)
167+
yield "Example of streaming an output"
168+
time.sleep(1)
169+
yield "\n\nOutput: " + input
170+
171+
172+
def output():
173+
state = me.state(State)
174+
if state.output or state.in_progress:
175+
with me.box(
176+
style=me.Style(
177+
background="#F0F4F9",
178+
padding=me.Padding.all(16),
179+
border_radius=16,
180+
margin=me.Margin(top=36),
181+
)
182+
):
183+
if state.output:
184+
me.markdown(state.output)
185+
if state.in_progress:
186+
with me.box(style=me.Style(margin=me.Margin(top=16))):
187+
me.progress_spinner()
188+
189+
190+
def footer():
191+
with me.box(
192+
style=me.Style(
193+
position="sticky",
194+
bottom=0,
195+
padding=me.Padding.symmetric(vertical=16, horizontal=16),
196+
width="100%",
197+
background="#F0F4F9",
198+
font_size=14,
199+
)
200+
):
201+
me.html(
202+
"Made with <a href='https://google.github.io/mesop/'>Mesop</a>",
203+
)

0 commit comments

Comments
 (0)