Simon Strandgaard commited on
Commit
b14ca77
·
1 Parent(s): 2ac4e20

The user settings are now stored in BrowserState, so the data survives restarting the server, and survives reloading the page.

Browse files
Files changed (2) hide show
  1. app.py +4 -4
  2. src/plan/app_text2plan.py +73 -45
app.py CHANGED
@@ -7,7 +7,7 @@ TEST-COMMIT: to make hugging face spaces rebuild. Again.
7
  if __name__ == "__main__":
8
  # from src.huggingface_spaces.print_gradio_info import print_gradio_info
9
  # print_gradio_info()
10
- # from src.plan.app_text2plan import run_app_text2plan
11
- # run_app_text2plan()
12
- from src.huggingface_spaces.app_state4 import demo
13
- demo.launch()
 
7
  if __name__ == "__main__":
8
  # from src.huggingface_spaces.print_gradio_info import print_gradio_info
9
  # print_gradio_info()
10
+ from src.plan.app_text2plan import run_app_text2plan
11
+ run_app_text2plan()
12
+ # from src.huggingface_spaces.app_state4 import demo
13
+ # demo.launch()
src/plan/app_text2plan.py CHANGED
@@ -12,6 +12,7 @@ import time
12
  import sys
13
  import threading
14
  import logging
 
15
  from dataclasses import dataclass
16
  from math import ceil
17
  from src.llm_factory import get_available_llms
@@ -134,9 +135,6 @@ class SessionState:
134
  """
135
  In a multi-user environment (e.g. Hugging Face Spaces), this class hold each users state.
136
  In a single-user environment, this class is used to hold the state of that lonely user.
137
-
138
- IDEA: Persist the user settings for longer. The settings survive a page refresh, but not a server restart.
139
- The browser has a local storage. Can Gradio access that, so that the settings are remembered between sessions?
140
  """
141
  def __init__(self):
142
  # Settings: the user's OpenRouter API key.
@@ -162,12 +160,48 @@ class SessionState:
162
  """
163
  return self
164
 
165
- def run_planner(submit_or_retry_button, plan_prompt, session_state: SessionState):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  """
167
  Generator function for launching the pipeline process and streaming updates.
168
  The session state is carried in a SessionState instance.
169
  """
170
 
 
 
 
 
 
 
 
 
 
171
  # Clear any previous stop signal.
172
  session_state.stop_event.clear()
173
 
@@ -360,28 +394,6 @@ def open_output_dir(session_state: SessionState):
360
  except Exception as e:
361
  return f"Failed to open directory: {e}", session_state
362
 
363
- def update_openrouter_api_key(openrouter_api_key, session_state: SessionState):
364
- """Updates the OpenRouter API key in the session state."""
365
- session_state.openrouter_api_key = openrouter_api_key
366
- return openrouter_api_key, session_state
367
-
368
- def update_model_radio(llm_model, session_state: SessionState):
369
- """Updates the llm_model in the session state"""
370
- session_state.llm_model = llm_model
371
- return llm_model, session_state
372
-
373
- def update_speedvsdetail_radio(speedvsdetail, session_state: SessionState):
374
- """Updates the speedvsdetail in the session state"""
375
- session_state.speedvsdetail = speedvsdetail
376
- return speedvsdetail, session_state
377
-
378
- def initialize_settings(session_state: SessionState):
379
- """Initializes the settings from session_state, if available."""
380
- return (session_state.openrouter_api_key,
381
- session_state.llm_model,
382
- session_state.speedvsdetail,
383
- session_state)
384
-
385
  def check_api_key(session_state: SessionState):
386
  """Checks if the API key is provided and returns a warning if not."""
387
  if CONFIG.visible_openrouter_api_key_textbox and (not session_state.openrouter_api_key or len(session_state.openrouter_api_key) == 0):
@@ -451,23 +463,24 @@ with gr.Blocks(title="PlanExe") as demo_text2plan:
451
 
452
  # Manage the state of the current user
453
  session_state = gr.State(SessionState())
 
454
 
455
  # Submit and Retry buttons call run_planner and update the state.
456
  submit_btn.click(
457
  fn=run_planner,
458
- inputs=[submit_btn, prompt_input, session_state],
459
  outputs=[output_markdown, download_output, session_state]
460
  ).then(
461
- fn=check_api_key, # Check after submitting.
462
  inputs=[session_state],
463
  outputs=[api_key_warning]
464
  )
465
  retry_btn.click(
466
  fn=run_planner,
467
- inputs=[retry_btn, prompt_input, session_state],
468
  outputs=[output_markdown, download_output, session_state]
469
  ).then(
470
- fn=check_api_key, # Check after retrying.
471
  inputs=[session_state],
472
  outputs=[api_key_warning]
473
  )
@@ -476,6 +489,10 @@ with gr.Blocks(title="PlanExe") as demo_text2plan:
476
  fn=stop_planner,
477
  inputs=session_state,
478
  outputs=[status_markdown, session_state]
 
 
 
 
479
  )
480
  # Open Output Dir button.
481
  open_dir_btn.click(
@@ -484,33 +501,44 @@ with gr.Blocks(title="PlanExe") as demo_text2plan:
484
  outputs=[status_markdown, session_state]
485
  )
486
 
 
487
  openrouter_api_key_text.change(
488
- fn=update_openrouter_api_key,
489
- inputs=[openrouter_api_key_text, session_state],
490
- outputs=[openrouter_api_key_text, session_state]
491
  ).then(
492
- fn=check_api_key, # Check when the API key changes.
493
  inputs=[session_state],
494
  outputs=[api_key_warning]
495
  )
 
496
  model_radio.change(
497
- fn=update_model_radio,
498
- inputs=[model_radio, session_state],
499
- outputs=[model_radio, session_state]
 
 
 
 
500
  )
 
501
  speedvsdetail_radio.change(
502
- fn=update_speedvsdetail_radio,
503
- inputs=[speedvsdetail_radio, session_state],
504
- outputs=[speedvsdetail_radio, session_state]
 
 
 
 
505
  )
506
 
507
-
508
  demo_text2plan.load(
509
- fn=initialize_settings,
510
- inputs=[session_state],
511
- outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
512
  ).then(
513
- fn=check_api_key, # Check on initial load.
514
  inputs=[session_state],
515
  outputs=[api_key_warning]
516
  )
 
12
  import sys
13
  import threading
14
  import logging
15
+ import json
16
  from dataclasses import dataclass
17
  from math import ceil
18
  from src.llm_factory import get_available_llms
 
135
  """
136
  In a multi-user environment (e.g. Hugging Face Spaces), this class hold each users state.
137
  In a single-user environment, this class is used to hold the state of that lonely user.
 
 
 
138
  """
139
  def __init__(self):
140
  # Settings: the user's OpenRouter API key.
 
160
  """
161
  return self
162
 
163
+ def initialize_browser_settings(browser_state, session_state: SessionState):
164
+ try:
165
+ settings = json.loads(browser_state) if browser_state else {}
166
+ except Exception:
167
+ settings = {}
168
+ openrouter_api_key = settings.get("openrouter_api_key_text", "")
169
+ model = settings.get("model_radio", available_model_names[0])
170
+ speedvsdetail = settings.get("speedvsdetail_radio", SpeedVsDetailEnum.ALL_DETAILS_BUT_SLOW)
171
+ session_state.openrouter_api_key = openrouter_api_key
172
+ session_state.llm_model = model
173
+ session_state.speedvsdetail = speedvsdetail
174
+ return openrouter_api_key, model, speedvsdetail, browser_state, session_state
175
+
176
+ def update_browser_settings_callback(openrouter_api_key, model, speedvsdetail, browser_state, session_state: SessionState):
177
+ try:
178
+ settings = json.loads(browser_state) if browser_state else {}
179
+ except Exception:
180
+ settings = {}
181
+ settings["openrouter_api_key_text"] = openrouter_api_key
182
+ settings["model_radio"] = model
183
+ settings["speedvsdetail_radio"] = speedvsdetail
184
+ updated_browser_state = json.dumps(settings)
185
+ session_state.openrouter_api_key = openrouter_api_key
186
+ session_state.llm_model = model
187
+ session_state.speedvsdetail = speedvsdetail
188
+ return updated_browser_state, openrouter_api_key, model, speedvsdetail, session_state
189
+
190
+ def run_planner(submit_or_retry_button, plan_prompt, browser_state, session_state: SessionState):
191
  """
192
  Generator function for launching the pipeline process and streaming updates.
193
  The session state is carried in a SessionState instance.
194
  """
195
 
196
+ # Sync persistent settings from BrowserState into session_state
197
+ try:
198
+ settings = json.loads(browser_state) if browser_state else {}
199
+ except Exception:
200
+ settings = {}
201
+ session_state.openrouter_api_key = settings.get("openrouter_api_key_text", session_state.openrouter_api_key)
202
+ session_state.llm_model = settings.get("model_radio", session_state.llm_model)
203
+ session_state.speedvsdetail = settings.get("speedvsdetail_radio", session_state.speedvsdetail)
204
+
205
  # Clear any previous stop signal.
206
  session_state.stop_event.clear()
207
 
 
394
  except Exception as e:
395
  return f"Failed to open directory: {e}", session_state
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  def check_api_key(session_state: SessionState):
398
  """Checks if the API key is provided and returns a warning if not."""
399
  if CONFIG.visible_openrouter_api_key_textbox and (not session_state.openrouter_api_key or len(session_state.openrouter_api_key) == 0):
 
463
 
464
  # Manage the state of the current user
465
  session_state = gr.State(SessionState())
466
+ browser_state = gr.BrowserState("", storage_key="Test", secret="Test")
467
 
468
  # Submit and Retry buttons call run_planner and update the state.
469
  submit_btn.click(
470
  fn=run_planner,
471
+ inputs=[submit_btn, prompt_input, browser_state, session_state],
472
  outputs=[output_markdown, download_output, session_state]
473
  ).then(
474
+ fn=check_api_key,
475
  inputs=[session_state],
476
  outputs=[api_key_warning]
477
  )
478
  retry_btn.click(
479
  fn=run_planner,
480
+ inputs=[retry_btn, prompt_input, browser_state, session_state],
481
  outputs=[output_markdown, download_output, session_state]
482
  ).then(
483
+ fn=check_api_key,
484
  inputs=[session_state],
485
  outputs=[api_key_warning]
486
  )
 
489
  fn=stop_planner,
490
  inputs=session_state,
491
  outputs=[status_markdown, session_state]
492
+ ).then(
493
+ fn=check_api_key,
494
+ inputs=[session_state],
495
+ outputs=[api_key_warning]
496
  )
497
  # Open Output Dir button.
498
  open_dir_btn.click(
 
501
  outputs=[status_markdown, session_state]
502
  )
503
 
504
+ # Unified change callbacks for settings.
505
  openrouter_api_key_text.change(
506
+ fn=update_browser_settings_callback,
507
+ inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, browser_state, session_state],
508
+ outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
509
  ).then(
510
+ fn=check_api_key,
511
  inputs=[session_state],
512
  outputs=[api_key_warning]
513
  )
514
+
515
  model_radio.change(
516
+ fn=update_browser_settings_callback,
517
+ inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, browser_state, session_state],
518
+ outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
519
+ ).then(
520
+ fn=check_api_key,
521
+ inputs=[session_state],
522
+ outputs=[api_key_warning]
523
  )
524
+
525
  speedvsdetail_radio.change(
526
+ fn=update_browser_settings_callback,
527
+ inputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, browser_state, session_state],
528
+ outputs=[browser_state, openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
529
+ ).then(
530
+ fn=check_api_key,
531
+ inputs=[session_state],
532
+ outputs=[api_key_warning]
533
  )
534
 
535
+ # Initialize settings on load from persistent browser_state.
536
  demo_text2plan.load(
537
+ fn=initialize_browser_settings,
538
+ inputs=[browser_state, session_state],
539
+ outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, browser_state, session_state]
540
  ).then(
541
+ fn=check_api_key,
542
  inputs=[session_state],
543
  outputs=[api_key_warning]
544
  )