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- app.py +4 -4
- 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 |
-
|
11 |
-
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
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,
|
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=
|
489 |
-
inputs=[openrouter_api_key_text, session_state],
|
490 |
-
outputs=[openrouter_api_key_text, session_state]
|
491 |
).then(
|
492 |
-
fn=check_api_key,
|
493 |
inputs=[session_state],
|
494 |
outputs=[api_key_warning]
|
495 |
)
|
|
|
496 |
model_radio.change(
|
497 |
-
fn=
|
498 |
-
inputs=[model_radio, session_state],
|
499 |
-
outputs=[model_radio, session_state]
|
|
|
|
|
|
|
|
|
500 |
)
|
|
|
501 |
speedvsdetail_radio.change(
|
502 |
-
fn=
|
503 |
-
inputs=[speedvsdetail_radio, session_state],
|
504 |
-
outputs=[speedvsdetail_radio, session_state]
|
|
|
|
|
|
|
|
|
505 |
)
|
506 |
|
507 |
-
|
508 |
demo_text2plan.load(
|
509 |
-
fn=
|
510 |
-
inputs=[session_state],
|
511 |
-
outputs=[openrouter_api_key_text, model_radio, speedvsdetail_radio, session_state]
|
512 |
).then(
|
513 |
-
fn=check_api_key,
|
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 |
)
|