Skip to content

Commit 82844a4

Browse files
committed
feat(ui): display missing API key errors in UI
This PR introduces proper error handling in the UI for missing API keys, addressing issue #188. Previously, missing API keys resulted in tracebacks in the console, but no clear error was shown in the UI. This made it difficult to understand what went wrong. Now, API key checks are performed at the start of the `get_llm_model` function in `src/utils/utils.py`. I've also added a `PROVIDER_DISPLAY_NAMES` constant for more user-friendly error messages and a `handle_api_key_error` function that leverages `gr.Error` to display clear error messages directly in the UI. If an API key is missing, you'll now see an error message right away. The `run_browser_agent` and `run_with_stream` functions in `webui.py` have been adjusted to ensure these `gr.Error` exceptions are handled properly.
1 parent dc41476 commit 82844a4

File tree

2 files changed

+35
-24
lines changed

2 files changed

+35
-24
lines changed

src/utils/utils.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,34 @@
1212

1313
from .llm import DeepSeekR1ChatOpenAI, DeepSeekR1ChatOllama
1414

15+
PROVIDER_DISPLAY_NAMES = {
16+
"openai": "OpenAI",
17+
"azure_openai": "Azure OpenAI",
18+
"anthropic": "Anthropic",
19+
"deepseek": "DeepSeek",
20+
"gemini": "Gemini"
21+
}
22+
1523
def get_llm_model(provider: str, **kwargs):
1624
"""
1725
获取LLM 模型
1826
:param provider: 模型类型
1927
:param kwargs:
2028
:return:
2129
"""
30+
if provider not in ["ollama"]:
31+
env_var = "GOOGLE_API_KEY" if provider == "gemini" else f"{provider.upper()}_API_KEY"
32+
api_key = kwargs.get("api_key", "") or os.getenv(env_var, "")
33+
if not api_key:
34+
handle_api_key_error(provider, env_var)
35+
kwargs["api_key"] = api_key
36+
2237
if provider == "anthropic":
2338
if not kwargs.get("base_url", ""):
2439
base_url = "https://api.anthropic.com"
2540
else:
2641
base_url = kwargs.get("base_url")
2742

28-
if not kwargs.get("api_key", ""):
29-
api_key = os.getenv("ANTHROPIC_API_KEY", "")
30-
else:
31-
api_key = kwargs.get("api_key")
32-
3343
return ChatAnthropic(
3444
model_name=kwargs.get("model_name", "claude-3-5-sonnet-20240620"),
3545
temperature=kwargs.get("temperature", 0.0),
@@ -42,11 +52,6 @@ def get_llm_model(provider: str, **kwargs):
4252
else:
4353
base_url = kwargs.get("base_url")
4454

45-
if not kwargs.get("api_key", ""):
46-
api_key = os.getenv("OPENAI_API_KEY", "")
47-
else:
48-
api_key = kwargs.get("api_key")
49-
5055
return ChatOpenAI(
5156
model=kwargs.get("model_name", "gpt-4o"),
5257
temperature=kwargs.get("temperature", 0.0),
@@ -59,11 +64,6 @@ def get_llm_model(provider: str, **kwargs):
5964
else:
6065
base_url = kwargs.get("base_url")
6166

62-
if not kwargs.get("api_key", ""):
63-
api_key = os.getenv("DEEPSEEK_API_KEY", "")
64-
else:
65-
api_key = kwargs.get("api_key")
66-
6767
if kwargs.get("model_name", "deepseek-chat") == "deepseek-reasoner":
6868
return DeepSeekR1ChatOpenAI(
6969
model=kwargs.get("model_name", "deepseek-reasoner"),
@@ -79,10 +79,6 @@ def get_llm_model(provider: str, **kwargs):
7979
api_key=api_key,
8080
)
8181
elif provider == "gemini":
82-
if not kwargs.get("api_key", ""):
83-
api_key = os.getenv("GOOGLE_API_KEY", "")
84-
else:
85-
api_key = kwargs.get("api_key")
8682
return ChatGoogleGenerativeAI(
8783
model=kwargs.get("model_name", "gemini-2.0-flash-exp"),
8884
temperature=kwargs.get("temperature", 0.0),
@@ -114,10 +110,6 @@ def get_llm_model(provider: str, **kwargs):
114110
base_url = os.getenv("AZURE_OPENAI_ENDPOINT", "")
115111
else:
116112
base_url = kwargs.get("base_url")
117-
if not kwargs.get("api_key", ""):
118-
api_key = os.getenv("AZURE_OPENAI_API_KEY", "")
119-
else:
120-
api_key = kwargs.get("api_key")
121113
return AzureChatOpenAI(
122114
model=kwargs.get("model_name", "gpt-4o"),
123115
temperature=kwargs.get("temperature", 0.0),
@@ -154,7 +146,17 @@ def update_model_dropdown(llm_provider, api_key=None, base_url=None):
154146
return gr.Dropdown(choices=model_names[llm_provider], value=model_names[llm_provider][0], interactive=True)
155147
else:
156148
return gr.Dropdown(choices=[], value="", interactive=True, allow_custom_value=True)
157-
149+
150+
def handle_api_key_error(provider: str, env_var: str):
151+
"""
152+
Handles the missing API key error by raising a gr.Error with a clear message.
153+
"""
154+
provider_display = PROVIDER_DISPLAY_NAMES.get(provider, provider.upper())
155+
raise gr.Error(
156+
f"💥 {provider_display} API key not found! 🔑 Please set the "
157+
f"`{env_var}` environment variable or provide it in the UI."
158+
)
159+
158160
def encode_image(img_path):
159161
if not img_path:
160162
return None

webui.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ async def run_browser_agent(
184184
gr.update(interactive=True) # Re-enable run button
185185
)
186186

187+
except gr.Error:
188+
raise
189+
187190
except Exception as e:
188191
import traceback
189192
traceback.print_exc()
@@ -535,6 +538,12 @@ async def run_with_stream(
535538
try:
536539
result = await agent_task
537540
final_result, errors, model_actions, model_thoughts, latest_videos, trace, history_file, stop_button, run_button = result
541+
except gr.Error:
542+
final_result = ""
543+
model_actions = ""
544+
model_thoughts = ""
545+
latest_videos = trace = history_file = None
546+
538547
except Exception as e:
539548
errors = f"Agent error: {str(e)}"
540549

0 commit comments

Comments
 (0)