Simon Strandgaard commited on
Commit
ceb7ac2
·
1 Parent(s): 437ee94

SessionState now remembers the settings. There is now a textfield for the user's own OpenRouter api key

Browse files
Files changed (1) hide show
  1. src/plan/app_text2plan.py +76 -14
src/plan/app_text2plan.py CHANGED
@@ -88,9 +88,18 @@ class MarkdownBuilder:
88
  class SessionState:
89
  """
90
  In a multi-user environment (e.g. Hugging Face Spaces), this class hold each users state.
91
- In a single-user environment, this class is used to hold the state of the current session.
 
 
 
92
  """
93
  def __init__(self):
 
 
 
 
 
 
94
  # Holds the subprocess.Popen object for the currently running pipeline process.
95
  self.active_proc = None
96
  # A threading.Event used to signal that the running process should stop.
@@ -108,14 +117,11 @@ class SessionState:
108
  """
109
  return self
110
 
111
- def run_planner(submit_or_retry_button, plan_prompt, llm_model, speedvsdetail, session_state: SessionState):
112
  """
113
  Generator function for launching the pipeline process and streaming updates.
114
  The session state is carried in a SessionState instance.
115
  """
116
- # Initialize session_state if needed.
117
- if session_state is None:
118
- session_state = SessionState()
119
 
120
  # Clear any previous stop signal.
121
  session_state.stop_event.clear()
@@ -154,8 +160,15 @@ def run_planner(submit_or_retry_button, plan_prompt, llm_model, speedvsdetail, s
154
  # Set environment variables for the pipeline.
155
  env = os.environ.copy()
156
  env["RUN_ID"] = run_id
157
- env["LLM_MODEL"] = llm_model
158
- env["SPEED_VS_DETAIL"] = speedvsdetail
 
 
 
 
 
 
 
159
 
160
  start_time = time.perf_counter()
161
  # Initialize the last zip creation time to be ZIP_INTERVAL_SECONDS in the past
@@ -269,8 +282,6 @@ def stop_planner(session_state: SessionState):
269
  """
270
  Sets a stop flag in the session_state and attempts to terminate the active process.
271
  """
272
- if session_state is None:
273
- session_state = SessionState()
274
 
275
  session_state.stop_event.set()
276
 
@@ -290,8 +301,6 @@ def open_output_dir(session_state: SessionState):
290
  """
291
  Opens the latest output directory in the native file explorer.
292
  """
293
- if session_state is None:
294
- session_state = SessionState()
295
 
296
  latest_run_dir = session_state.latest_run_dir
297
  if not latest_run_dir or not os.path.exists(latest_run_dir):
@@ -308,6 +317,29 @@ def open_output_dir(session_state: SessionState):
308
  except Exception as e:
309
  return f"Failed to open directory: {e}", session_state
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  # Build the Gradio UI using Blocks.
312
  with gr.Blocks(title="PlanExe") as demo_text2plan:
313
  gr.Markdown("# PlanExe: crack open pandora’s box of ideas")
@@ -354,24 +386,31 @@ with gr.Blocks(title="PlanExe") as demo_text2plan:
354
  label="Speed vs Detail",
355
  interactive=True
356
  )
 
 
 
 
 
 
357
 
358
  with gr.Tab("Join the community"):
359
  gr.Markdown("""
360
  - [GitHub](https://github.com/neoneye/PlanExe) the source code.
361
  - [Discord](https://neoneye.github.io/PlanExe-web/discord) join the community. Suggestions, feedback, and questions are welcome.
362
  """)
363
- # Create a hidden state to hold our SessionState instance.
 
364
  session_state = gr.State(SessionState())
365
 
366
  # Submit and Retry buttons call run_planner and update the state.
367
  submit_btn.click(
368
  fn=run_planner,
369
- inputs=[submit_btn, prompt_input, model_radio, speedvsdetail_radio, session_state],
370
  outputs=[output_markdown, download_output, session_state]
371
  )
372
  retry_btn.click(
373
  fn=run_planner,
374
- inputs=[retry_btn, prompt_input, model_radio, speedvsdetail_radio, session_state],
375
  outputs=[output_markdown, download_output, session_state]
376
  )
377
  # The Stop button uses the state to terminate the running process.
@@ -387,6 +426,29 @@ with gr.Blocks(title="PlanExe") as demo_text2plan:
387
  outputs=[status_markdown, session_state]
388
  )
389
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  if __name__ == "__main__":
391
  # print("Environment variables Gradio:\n" + get_env_as_string() + "\n\n\n")
392
 
 
88
  class SessionState:
89
  """
90
  In a multi-user environment (e.g. Hugging Face Spaces), this class hold each users state.
91
+ In a single-user environment, this class is used to hold the state of that lonely user.
92
+
93
+ IDEA: Persist the user settings for longer. The settings survive a page refresh, but not a server restart.
94
+ The browser has a local storage. Can Gradio access that, so that the settings are remembered between sessions?
95
  """
96
  def __init__(self):
97
+ # Settings: the user's OpenRouter API key.
98
+ self.openrouter_api_key = "" # Initialize to empty string
99
+ # Settings: The model that the user has picked.
100
+ self.llm_model = available_model_names[0]
101
+ # Settings: The speedvsdetail that the user has picked.
102
+ self.speedvsdetail = SpeedVsDetailEnum.ALL_DETAILS_BUT_SLOW
103
  # Holds the subprocess.Popen object for the currently running pipeline process.
104
  self.active_proc = None
105
  # A threading.Event used to signal that the running process should stop.
 
117
  """
118
  return self
119
 
120
+ def run_planner(submit_or_retry_button, plan_prompt, session_state: SessionState):
121
  """
122
  Generator function for launching the pipeline process and streaming updates.
123
  The session state is carried in a SessionState instance.
124
  """
 
 
 
125
 
126
  # Clear any previous stop signal.
127
  session_state.stop_event.clear()
 
160
  # Set environment variables for the pipeline.
161
  env = os.environ.copy()
162
  env["RUN_ID"] = run_id
163
+ env["LLM_MODEL"] = session_state.llm_model
164
+ env["SPEED_VS_DETAIL"] = session_state.speedvsdetail
165
+
166
+ # If there is a non-empty OpenRouter API key, set it as an environment variable.
167
+ if session_state.openrouter_api_key and len(session_state.openrouter_api_key) > 0:
168
+ print("Setting OpenRouter API key as environment variable.")
169
+ env["OPENROUTER_API_KEY"] = session_state.openrouter_api_key
170
+ else:
171
+ print("No OpenRouter API key provided.")
172
 
173
  start_time = time.perf_counter()
174
  # Initialize the last zip creation time to be ZIP_INTERVAL_SECONDS in the past
 
282
  """
283
  Sets a stop flag in the session_state and attempts to terminate the active process.
284
  """
 
 
285
 
286
  session_state.stop_event.set()
287
 
 
301
  """
302
  Opens the latest output directory in the native file explorer.
303
  """
 
 
304
 
305
  latest_run_dir = session_state.latest_run_dir
306
  if not latest_run_dir or not os.path.exists(latest_run_dir):
 
317
  except Exception as e:
318
  return f"Failed to open directory: {e}", session_state
319
 
320
+ def update_openrouter_api_key(openrouter_api_key, session_state: SessionState):
321
+ """Updates the OpenRouter API key in the session state."""
322
+ session_state.openrouter_api_key = openrouter_api_key
323
+ return openrouter_api_key, session_state
324
+
325
+ def update_model_radio(llm_model, session_state: SessionState):
326
+ """Updates the llm_model in the session state"""
327
+ session_state.llm_model = llm_model
328
+ return llm_model, session_state
329
+
330
+ def update_speedvsdetail_radio(speedvsdetail, session_state: SessionState):
331
+ """Updates the speedvsdetail in the session state"""
332
+ session_state.speedvsdetail = speedvsdetail
333
+ return speedvsdetail, session_state
334
+
335
+ def initialize_settings(session_state: SessionState):
336
+ """Initializes the settings from session_state, if available."""
337
+ return (session_state.openrouter_api_key,
338
+ session_state.llm_model,
339
+ session_state.speedvsdetail,
340
+ session_state)
341
+
342
+
343
  # Build the Gradio UI using Blocks.
344
  with gr.Blocks(title="PlanExe") as demo_text2plan:
345
  gr.Markdown("# PlanExe: crack open pandora’s box of ideas")
 
386
  label="Speed vs Detail",
387
  interactive=True
388
  )
389
+ openrouter_api_key_text = gr.Textbox(
390
+ label="OpenRouter API Key",
391
+ type="password",
392
+ placeholder="Enter your OpenRouter API key (optional)",
393
+ info="Sign up at [OpenRouter](https://openrouter.ai/) to get an API key. A small top-up (e.g. 5 USD) is needed to access paid models."
394
+ )
395
 
396
  with gr.Tab("Join the community"):
397
  gr.Markdown("""
398
  - [GitHub](https://github.com/neoneye/PlanExe) the source code.
399
  - [Discord](https://neoneye.github.io/PlanExe-web/discord) join the community. Suggestions, feedback, and questions are welcome.
400
  """)
401
+
402
+ # Manage the state of the current user
403
  session_state = gr.State(SessionState())
404
 
405
  # Submit and Retry buttons call run_planner and update the state.
406
  submit_btn.click(
407
  fn=run_planner,
408
+ inputs=[submit_btn, prompt_input, session_state],
409
  outputs=[output_markdown, download_output, session_state]
410
  )
411
  retry_btn.click(
412
  fn=run_planner,
413
+ inputs=[retry_btn, prompt_input, session_state],
414
  outputs=[output_markdown, download_output, session_state]
415
  )
416
  # The Stop button uses the state to terminate the running process.
 
426
  outputs=[status_markdown, session_state]
427
  )
428
 
429
+ openrouter_api_key_text.change(
430
+ fn=update_openrouter_api_key,
431
+ inputs=[openrouter_api_key_text, session_state],
432
+ outputs=[openrouter_api_key_text, session_state]
433
+ )
434
+ model_radio.change(
435
+ fn=update_model_radio,
436
+ inputs=[model_radio, session_state],
437
+ outputs=[model_radio, session_state]
438
+ )
439
+ speedvsdetail_radio.change(
440
+ fn=update_speedvsdetail_radio,
441
+ inputs=[speedvsdetail_radio, session_state],
442
+ outputs=[speedvsdetail_radio, session_state]
443
+ )
444
+
445
+
446
+ demo_text2plan.load(
447
+ fn=initialize_settings,
448
+ inputs=[session_state],
449
+ outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
450
+ )
451
+
452
  if __name__ == "__main__":
453
  # print("Environment variables Gradio:\n" + get_env_as_string() + "\n\n\n")
454