Richard commited on
Commit
52fcaad
·
1 Parent(s): dc4b9e8

Add runner token support

Browse files

- Add help dialog
- Various refactorings

Files changed (5) hide show
  1. README.md +13 -0
  2. components/button.py +6 -6
  3. constants.py +20 -0
  4. main.py +48 -9
  5. 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.content_button(
17
- on_click=on_click,
18
- key=key,
19
- type="icon",
20
- ):
21
- with me.tooltip(message=tooltip):
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 DEFAULT_URL, PROMPT_MODE_REVISE, PROMPT_MODE_GENERATE
 
 
 
 
 
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
- label="API Key", key="api_key", on_blur=handlers.on_update_input, disabled=state.loading
 
 
 
 
 
173
  )
174
  me.select(
175
  label="Model",
@@ -190,9 +218,19 @@ def main():
190
  )
191
  with me.box():
192
  me.input(
193
- value=DEFAULT_URL,
194
- label="URL",
195
- key="url",
 
 
 
 
 
 
 
 
 
 
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.url + state.url_path
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 runner."""
346
  state = me.state(State)
347
  state.code_placeholder = state.code
348
  yield
349
  result = requests.post(
350
- state.url + "/exec", data={"code": base64.b64encode(state.code.encode("utf-8"))}
 
351
  )
352
  if result.status_code == 200:
353
- state.url_path = result.content.decode("utf-8")
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
- url: str = c.DEFAULT_URL
 
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
- url_path: str = "/"
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