Spaces:
Running
Running
Richard
commited on
Commit
·
52fcaad
1
Parent(s):
dc4b9e8
Add runner token support
Browse files- Add help dialog
- Various refactorings
- README.md +13 -0
- components/button.py +6 -6
- constants.py +20 -0
- main.py +48 -9
- state.py +7 -3
README.md
CHANGED
@@ -26,6 +26,19 @@ pip install -r requirements.txt
|
|
26 |
mesop main.py
|
27 |
```
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
You will need a Gemini API key to use the Mesop app generate functionality.
|
30 |
|
31 |
### The runner
|
|
|
26 |
mesop main.py
|
27 |
```
|
28 |
|
29 |
+
#### Environment variables
|
30 |
+
|
31 |
+
The editor supports the following environment variables. These are mainly useful for
|
32 |
+
local development where you don't want to keep entering your API Key and runner token
|
33 |
+
after every reload.
|
34 |
+
|
35 |
+
```
|
36 |
+
GEMINI_API_KEY=you-app-key
|
37 |
+
MESOP_APP_MAKER_RUNNER_URL=https://example.com
|
38 |
+
MESOP_APP_MAKER_RUNNER_TOKEN=your-secret-token
|
39 |
+
MESOP_APP_MAKER_SHOW_HELP=0
|
40 |
+
```
|
41 |
+
|
42 |
You will need a Gemini API key to use the Mesop app generate functionality.
|
43 |
|
44 |
### The runner
|
components/button.py
CHANGED
@@ -13,12 +13,12 @@ def toolbar_button(
|
|
13 |
on_click: Callable[[me.ClickEvent], Any] | None = None,
|
14 |
key: str = "",
|
15 |
):
|
16 |
-
with me.
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
me.icon(icon)
|
23 |
|
24 |
|
|
|
13 |
on_click: Callable[[me.ClickEvent], Any] | None = None,
|
14 |
key: str = "",
|
15 |
):
|
16 |
+
with me.tooltip(message=tooltip):
|
17 |
+
with me.content_button(
|
18 |
+
on_click=on_click,
|
19 |
+
key=key,
|
20 |
+
type="icon",
|
21 |
+
):
|
22 |
me.icon(icon)
|
23 |
|
24 |
|
constants.py
CHANGED
@@ -8,3 +8,23 @@ def app():
|
|
8 |
""".strip()
|
9 |
PROMPT_MODE_GENERATE = "Generate"
|
10 |
PROMPT_MODE_REVISE = "Revise"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
""".strip()
|
9 |
PROMPT_MODE_GENERATE = "Generate"
|
10 |
PROMPT_MODE_REVISE = "Revise"
|
11 |
+
|
12 |
+
HELP_TEXT = """
|
13 |
+
**Generating Mesop Apps**
|
14 |
+
|
15 |
+
- Provide a Gemini API Key in the Settings panel.
|
16 |
+
- Click the lightning bolt button to open the prompt panel.
|
17 |
+
- Enter your prompt and generate your app.
|
18 |
+
- Inspect the generated code in the editor.
|
19 |
+
- Press the run/play button to execute and view your code
|
20 |
+
- *Requires Mesop App Runner instance.*
|
21 |
+
|
22 |
+
**Setting up a Mesop Runner instance**
|
23 |
+
|
24 |
+
*If running on Hugging Face, you will need to fork the Mesop App Runner space.*
|
25 |
+
|
26 |
+
- Start up an instance of the [Mesop App Runner](https://github.com/richard-to/mesop-app-runner).
|
27 |
+
- See [Github repository](https://github.com/richard-to/mesop-app-runner) for more details.
|
28 |
+
- Provide the Runner URL to your instance.
|
29 |
+
- Provide the Runner Token to your runner instance.
|
30 |
+
""".strip()
|
main.py
CHANGED
@@ -8,7 +8,12 @@ import mesop.labs as mel
|
|
8 |
import components as mex
|
9 |
import handlers
|
10 |
import llm
|
11 |
-
from constants import
|
|
|
|
|
|
|
|
|
|
|
12 |
from state import State
|
13 |
from web_components import code_mirror_editor_component
|
14 |
from web_components import AsyncAction
|
@@ -65,6 +70,17 @@ def main():
|
|
65 |
on_click=handlers.on_hide_component,
|
66 |
)
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
# Generate code panel
|
69 |
with mex.panel(
|
70 |
is_open=state.show_generate_panel,
|
@@ -151,6 +167,13 @@ def main():
|
|
151 |
on_click=on_click_theme_brightness,
|
152 |
)
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
if state.menu_open and state.menu_open_type == "settings":
|
155 |
with me.box(
|
156 |
style=me.Style(
|
@@ -169,7 +192,12 @@ def main():
|
|
169 |
style=me.Style(font_weight="bold", margin=me.Margin(bottom=10)),
|
170 |
)
|
171 |
me.input(
|
172 |
-
|
|
|
|
|
|
|
|
|
|
|
173 |
)
|
174 |
me.select(
|
175 |
label="Model",
|
@@ -190,9 +218,19 @@ def main():
|
|
190 |
)
|
191 |
with me.box():
|
192 |
me.input(
|
193 |
-
value=
|
194 |
-
label="URL",
|
195 |
-
key="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
on_blur=handlers.on_update_input,
|
197 |
style=me.Style(width="100%"),
|
198 |
disabled=state.loading,
|
@@ -336,21 +374,22 @@ def on_load_url(e: me.ClickEvent):
|
|
336 |
state = me.state(State)
|
337 |
state.code_placeholder = state.code
|
338 |
yield
|
339 |
-
state.loaded_url = state.
|
340 |
state.iframe_index += 1
|
341 |
yield
|
342 |
|
343 |
|
344 |
def on_run_code(e: me.ClickEvent):
|
345 |
-
"""Tries to upload code to the Mesop app
|
346 |
state = me.state(State)
|
347 |
state.code_placeholder = state.code
|
348 |
yield
|
349 |
result = requests.post(
|
350 |
-
state.
|
|
|
351 |
)
|
352 |
if result.status_code == 200:
|
353 |
-
state.
|
354 |
yield from on_load_url(e)
|
355 |
else:
|
356 |
state.show_error_dialog = True
|
|
|
8 |
import components as mex
|
9 |
import handlers
|
10 |
import llm
|
11 |
+
from constants import (
|
12 |
+
DEFAULT_URL,
|
13 |
+
PROMPT_MODE_REVISE,
|
14 |
+
PROMPT_MODE_GENERATE,
|
15 |
+
HELP_TEXT,
|
16 |
+
)
|
17 |
from state import State
|
18 |
from web_components import code_mirror_editor_component
|
19 |
from web_components import AsyncAction
|
|
|
70 |
on_click=handlers.on_hide_component,
|
71 |
)
|
72 |
|
73 |
+
# Help dialog
|
74 |
+
with mex.dialog(state.show_help_dialog):
|
75 |
+
me.text("Usage Instructions", type="headline-6")
|
76 |
+
me.markdown(HELP_TEXT)
|
77 |
+
with mex.dialog_actions():
|
78 |
+
me.button(
|
79 |
+
"Close",
|
80 |
+
key="show_help_dialog",
|
81 |
+
on_click=handlers.on_hide_component,
|
82 |
+
)
|
83 |
+
|
84 |
# Generate code panel
|
85 |
with mex.panel(
|
86 |
is_open=state.show_generate_panel,
|
|
|
167 |
on_click=on_click_theme_brightness,
|
168 |
)
|
169 |
|
170 |
+
mex.toolbar_button(
|
171 |
+
icon="help",
|
172 |
+
tooltip="Help",
|
173 |
+
key="show_help_dialog",
|
174 |
+
on_click=handlers.on_show_component,
|
175 |
+
)
|
176 |
+
|
177 |
if state.menu_open and state.menu_open_type == "settings":
|
178 |
with me.box(
|
179 |
style=me.Style(
|
|
|
192 |
style=me.Style(font_weight="bold", margin=me.Margin(bottom=10)),
|
193 |
)
|
194 |
me.input(
|
195 |
+
type="password",
|
196 |
+
label="Gemini API Key",
|
197 |
+
key="api_key",
|
198 |
+
value=state.api_key,
|
199 |
+
on_blur=handlers.on_update_input,
|
200 |
+
disabled=state.loading,
|
201 |
)
|
202 |
me.select(
|
203 |
label="Model",
|
|
|
218 |
)
|
219 |
with me.box():
|
220 |
me.input(
|
221 |
+
value=state.runner_url,
|
222 |
+
label="Runner URL",
|
223 |
+
key="runner_url",
|
224 |
+
on_blur=handlers.on_update_input,
|
225 |
+
style=me.Style(width="100%"),
|
226 |
+
disabled=state.loading,
|
227 |
+
)
|
228 |
+
with me.box():
|
229 |
+
me.input(
|
230 |
+
type="password",
|
231 |
+
value=state.runner_token,
|
232 |
+
label="Runner Token",
|
233 |
+
key="runner_token",
|
234 |
on_blur=handlers.on_update_input,
|
235 |
style=me.Style(width="100%"),
|
236 |
disabled=state.loading,
|
|
|
374 |
state = me.state(State)
|
375 |
state.code_placeholder = state.code
|
376 |
yield
|
377 |
+
state.loaded_url = state.runner_url.removesuffix("/") + state.runner_url_path
|
378 |
state.iframe_index += 1
|
379 |
yield
|
380 |
|
381 |
|
382 |
def on_run_code(e: me.ClickEvent):
|
383 |
+
"""Tries to upload code to the Mesop app Runner."""
|
384 |
state = me.state(State)
|
385 |
state.code_placeholder = state.code
|
386 |
yield
|
387 |
result = requests.post(
|
388 |
+
state.runner_url.removesuffix("/") + "/exec",
|
389 |
+
data={"token": state.runner_token, "code": base64.b64encode(state.code.encode("utf-8"))},
|
390 |
)
|
391 |
if result.status_code == 200:
|
392 |
+
state.runner_url_path = result.content.decode("utf-8")
|
393 |
yield from on_load_url(e)
|
394 |
else:
|
395 |
state.show_error_dialog = True
|
state.py
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
import mesop as me
|
2 |
|
3 |
import constants as c
|
@@ -11,9 +13,10 @@ class State:
|
|
11 |
info: str
|
12 |
|
13 |
# Settings
|
14 |
-
api_key: str
|
15 |
model: str = "gemini-1.5-flash"
|
16 |
-
|
|
|
17 |
|
18 |
# Generate prompt panel
|
19 |
prompt_mode: str = "Generate"
|
@@ -29,7 +32,7 @@ class State:
|
|
29 |
|
30 |
# App preview
|
31 |
run_result: str
|
32 |
-
|
33 |
loaded_url: str
|
34 |
iframe_index: int
|
35 |
|
@@ -42,6 +45,7 @@ class State:
|
|
42 |
show_generate_panel: bool = False
|
43 |
show_prompt_history_panel: bool = False
|
44 |
show_status_snackbar: bool = False
|
|
|
45 |
|
46 |
# Async action
|
47 |
async_action_name: str
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
import mesop as me
|
4 |
|
5 |
import constants as c
|
|
|
13 |
info: str
|
14 |
|
15 |
# Settings
|
16 |
+
api_key: str = os.getenv("GEMINI_API_KEY", "")
|
17 |
model: str = "gemini-1.5-flash"
|
18 |
+
runner_url: str = os.getenv("MESOP_APP_MAKER_RUNNER_URL", c.DEFAULT_URL)
|
19 |
+
runner_token: str = os.getenv("MESOP_APP_MAKER_RUNNER_TOKEN", "")
|
20 |
|
21 |
# Generate prompt panel
|
22 |
prompt_mode: str = "Generate"
|
|
|
32 |
|
33 |
# App preview
|
34 |
run_result: str
|
35 |
+
runner_url_path: str = "/"
|
36 |
loaded_url: str
|
37 |
iframe_index: int
|
38 |
|
|
|
45 |
show_generate_panel: bool = False
|
46 |
show_prompt_history_panel: bool = False
|
47 |
show_status_snackbar: bool = False
|
48 |
+
show_help_dialog: bool = bool(int(os.getenv("MESOP_APP_MAKER_SHOW_HELP", "0")))
|
49 |
|
50 |
# Async action
|
51 |
async_action_name: str
|