2stacks Claude commited on
Commit
d5e1565
·
verified ·
1 Parent(s): 9f70d46

Implement proper Hugging Face OAuth authentication

Browse files

- Add gr.LoginButton to the sidebar for OAuth login
- Use gr.OAuthToken type hints for automatic token injection
- Update create_agent() to accept oauth_token parameter
- Create interact_with_agent_oauth() wrapper as a generator
- Update all event handlers to use OAuth-aware methods
- Priority: OAuth token > HF_TOKEN env var > CLI login

This ensures users can properly authenticate via OAuth on HF Spaces
and the agent receives the correct authentication token for API calls.

Fixes: "You must provide an api_key to work with nscale API" error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +15 -4
  2. my_ui.py +22 -5
app.py CHANGED
@@ -100,8 +100,13 @@ def get_tavily_search_mcp(api_key):
100
  }
101
 
102
 
103
- def create_agent(tavily_api_key=None):
104
- """Create an agent with the specified Tavily API key (or use environment variable)."""
 
 
 
 
 
105
  # Use provided API key or fall back to environment variable
106
  api_key = tavily_api_key or TAVILY_API_KEY
107
 
@@ -119,8 +124,14 @@ def create_agent(tavily_api_key=None):
119
  mcp_client = MCPClient(mcp_servers, structured_output=False)
120
 
121
  # Create model with user-specified parameters
122
- # On HF Spaces with OAuth, HF_TOKEN is automatically set; locally use get_token() or .env
123
- hf_token = os.getenv("HF_TOKEN") or get_token()
 
 
 
 
 
 
124
  model = InferenceClientModel(
125
  max_tokens=2096,
126
  temperature=0.5,
 
100
  }
101
 
102
 
103
+ def create_agent(tavily_api_key=None, oauth_token=None):
104
+ """Create an agent with the specified Tavily API key and OAuth token.
105
+
106
+ Args:
107
+ tavily_api_key: Optional Tavily API key for web search
108
+ oauth_token: OAuth token from Gradio (gr.OAuthToken | None)
109
+ """
110
  # Use provided API key or fall back to environment variable
111
  api_key = tavily_api_key or TAVILY_API_KEY
112
 
 
124
  mcp_client = MCPClient(mcp_servers, structured_output=False)
125
 
126
  # Create model with user-specified parameters
127
+ # Priority: OAuth token from Gradio > HF_TOKEN env var > get_token() from CLI login
128
+ if oauth_token is not None:
129
+ # On HF Spaces, use the OAuth token provided by Gradio
130
+ hf_token = oauth_token.token if hasattr(oauth_token, 'token') else oauth_token
131
+ else:
132
+ # Fallback to environment variable or CLI login
133
+ hf_token = os.getenv("HF_TOKEN") or get_token()
134
+
135
  model = InferenceClientModel(
136
  max_tokens=2096,
137
  temperature=0.5,
my_ui.py CHANGED
@@ -22,20 +22,31 @@ class CustomGradioUI(GradioUI):
22
  self.allowed_file_types = allowed_file_types or [".pdf", ".docx", ".txt"]
23
  self.examples = examples or []
24
 
25
- def update_api_key(self, api_key, current_key):
26
  """Update the agent with a new API key."""
27
  if api_key and api_key != current_key:
28
  # Recreate the agent with the new API key
29
- self.agent = self.agent_factory(tavily_api_key=api_key)
30
  return api_key, gr.Markdown("✓ API key updated successfully", visible=True)
31
  elif not api_key and current_key:
32
  # Reset to default (env var)
33
- self.agent = self.agent_factory()
34
  return "", gr.Markdown(
35
  "API key cleared, using environment variable if set", visible=True
36
  )
37
  return current_key, gr.Markdown("", visible=False)
38
 
 
 
 
 
 
 
 
 
 
 
 
39
  def create_app(self):
40
  """Override create_app to use custom allowed_file_types."""
41
 
@@ -57,6 +68,8 @@ class CustomGradioUI(GradioUI):
57
  else ""
58
  )
59
  )
 
 
60
 
61
  with gr.Group():
62
  gr.Markdown("**Your request**", container=True)
@@ -144,7 +157,9 @@ class CustomGradioUI(GradioUI):
144
  [text_input, file_uploads_log],
145
  [stored_messages, text_input, submit_btn],
146
  ).then(
147
- self.interact_with_agent, [stored_messages, chatbot, session_state], [chatbot]
 
 
148
  ).then(
149
  lambda: (
150
  gr.Textbox(
@@ -162,7 +177,9 @@ class CustomGradioUI(GradioUI):
162
  [text_input, file_uploads_log],
163
  [stored_messages, text_input, submit_btn],
164
  ).then(
165
- self.interact_with_agent, [stored_messages, chatbot, session_state], [chatbot]
 
 
166
  ).then(
167
  lambda: (
168
  gr.Textbox(
 
22
  self.allowed_file_types = allowed_file_types or [".pdf", ".docx", ".txt"]
23
  self.examples = examples or []
24
 
25
+ def update_api_key(self, api_key, current_key, oauth_token: gr.OAuthToken | None = None):
26
  """Update the agent with a new API key."""
27
  if api_key and api_key != current_key:
28
  # Recreate the agent with the new API key
29
+ self.agent = self.agent_factory(tavily_api_key=api_key, oauth_token=oauth_token)
30
  return api_key, gr.Markdown("✓ API key updated successfully", visible=True)
31
  elif not api_key and current_key:
32
  # Reset to default (env var)
33
+ self.agent = self.agent_factory(oauth_token=oauth_token)
34
  return "", gr.Markdown(
35
  "API key cleared, using environment variable if set", visible=True
36
  )
37
  return current_key, gr.Markdown("", visible=False)
38
 
39
+ def interact_with_agent_oauth(self, stored_messages, chatbot, session_state, oauth_token: gr.OAuthToken | None = None):
40
+ """Wrapper for interact_with_agent that recreates agent with OAuth token."""
41
+ # Recreate agent with the OAuth token before interaction
42
+ if oauth_token is not None:
43
+ # Get current API key if any
44
+ current_api_key = session_state.get("tavily_api_key", None)
45
+ self.agent = self.agent_factory(tavily_api_key=current_api_key, oauth_token=oauth_token)
46
+
47
+ # Call the parent's interact_with_agent method and yield all results
48
+ yield from self.interact_with_agent(stored_messages, chatbot, session_state)
49
+
50
  def create_app(self):
51
  """Override create_app to use custom allowed_file_types."""
52
 
 
68
  else ""
69
  )
70
  )
71
+ # Add OAuth Login Button
72
+ gr.LoginButton()
73
 
74
  with gr.Group():
75
  gr.Markdown("**Your request**", container=True)
 
157
  [text_input, file_uploads_log],
158
  [stored_messages, text_input, submit_btn],
159
  ).then(
160
+ self.interact_with_agent_oauth,
161
+ [stored_messages, chatbot, session_state],
162
+ [chatbot]
163
  ).then(
164
  lambda: (
165
  gr.Textbox(
 
177
  [text_input, file_uploads_log],
178
  [stored_messages, text_input, submit_btn],
179
  ).then(
180
+ self.interact_with_agent_oauth,
181
+ [stored_messages, chatbot, session_state],
182
+ [chatbot]
183
  ).then(
184
  lambda: (
185
  gr.Textbox(