Spaces:
Running
Running
File size: 16,364 Bytes
dab7275 4db4e9d dab7275 4db4e9d dab7275 4449927 dab7275 4449927 dab7275 4db4e9d dab7275 4449927 dab7275 4449927 dab7275 4449927 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 4db4e9d dab7275 fe72fcb dab7275 fe72fcb dab7275 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
"""
Settings Screen for TraceMind-AI
Allows users to configure API keys for Gemini, HuggingFace, Modal, and LLM providers
"""
import gradio as gr
import os
# Note: Removed _get_llm_keys_as_env_string() to prevent exposing environment variables
# in the UI for security reasons. Users should explicitly enter keys needed for jobs.
def _parse_env_string(env_string):
"""
Parse ENV-formatted string into a dictionary
Args:
env_string: Multi-line string in KEY=value format
Returns:
dict: Parsed key-value pairs
"""
result = {}
if not env_string:
return result
for line in env_string.strip().split("\n"):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
result[key.strip()] = value.strip()
return result
def create_settings_screen():
"""
Create the settings screen for API key configuration
Returns:
gr.Column: Gradio Column component for settings (can be shown/hidden)
"""
with gr.Column(visible=False) as settings_interface:
gr.Markdown("""
# βοΈ Settings
Configure your API keys to use TraceMind features. These keys are stored only in your browser session and are never saved to our servers.
""")
with gr.Accordion("π API Key Configuration", open=True):
gr.Markdown("""
### Why provide API keys?
TraceMind uses external services to provide intelligent analysis and insights:
- **Google Gemini API**: Powers the MCP server for leaderboard analysis, cost estimation, and trace debugging
- **HuggingFace Token**: Required to access evaluation datasets and results
**For Judges & Visitors**: Please enter your own API keys to prevent credit issues during evaluation.
""")
# Gemini API Key
with gr.Row():
with gr.Column(scale=4):
gemini_api_key = gr.Textbox(
label="Google Gemini API Key",
placeholder="Enter your Gemini API key (starts with 'AIza...')",
type="password",
value=os.environ.get("GEMINI_API_KEY", ""),
info="Get your free API key at: https://ai.google.dev/"
)
with gr.Column(scale=1):
gemini_status = gr.Markdown("βͺ Not configured")
# HuggingFace Token
with gr.Row():
with gr.Column(scale=4):
hf_token = gr.Textbox(
label="HuggingFace Token (Required for Job Submission)",
placeholder="Enter your HF token (starts with 'hf_...')",
type="password",
value=os.environ.get("HF_TOKEN", ""),
info="β οΈ Token needs: Read + Write + Run Jobs permissions | Pro account required"
)
with gr.Column(scale=1):
hf_status = gr.Markdown("βͺ Not configured")
# Modal API Key
with gr.Row():
with gr.Column(scale=4):
modal_api_key = gr.Textbox(
label="Modal API Key (Optional)",
placeholder="Enter your Modal API key (starts with 'ak-...')",
type="password",
value=os.environ.get("MODAL_TOKEN_ID", ""),
info="Get your key at: https://modal.com/settings/tokens"
)
with gr.Column(scale=1):
modal_status = gr.Markdown("βͺ Not configured")
# Modal API Secret
with gr.Row():
with gr.Column(scale=4):
modal_api_secret = gr.Textbox(
label="Modal API Secret (Optional)",
placeholder="Enter your Modal API secret (starts with 'as-...')",
type="password",
value=os.environ.get("MODAL_TOKEN_SECRET", ""),
info="Required if using Modal for job execution"
)
with gr.Column(scale=1):
modal_secret_status = gr.Markdown("βͺ Not configured")
# LLM Provider API Keys (Multi-line for convenience)
gr.Markdown("""
### LLM Provider API Keys (Optional)
Paste your API keys in ENV format below. These are needed for running evaluations with API-based models.
""")
llm_api_keys = gr.Textbox(
label="LLM Provider API Keys",
placeholder="""OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=AIza...
GEMINI_API_KEY=AIza...
COHERE_API_KEY=...
MISTRAL_API_KEY=...
TOGETHER_API_KEY=...
GROQ_API_KEY=gsk_...
REPLICATE_API_TOKEN=r8_...
ANYSCALE_API_KEY=...
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-west-2
AZURE_OPENAI_API_KEY=...
AZURE_OPENAI_ENDPOINT=https://...
LITELLM_API_KEY=...""",
lines=10,
value="", # Don't expose existing env vars
info="Enter one key=value per line. These will be passed to evaluation jobs."
)
# Save button
with gr.Row():
save_btn = gr.Button("πΎ Save API Keys", variant="primary")
test_btn = gr.Button("π§ͺ Test Connection", variant="secondary")
# Status message
status_message = gr.Markdown("")
with gr.Accordion("π How to Get API Keys", open=False):
gr.Markdown("""
### Google Gemini API Key
1. Go to [Google AI Studio](https://ai.google.dev/)
2. Click "Get API Key" in the top right
3. Create a new project or select an existing one
4. Generate an API key
5. Copy the key (starts with `AIza...`)
**Free Tier**: 60 requests per minute, suitable for testing and demos
---
### HuggingFace Token
**For Job Submission (Required):**
1. Go to [HuggingFace Settings](https://huggingface.co/settings/tokens)
2. Click "New token"
3. Give it a name (e.g., "TraceMind Job Submission")
4. Select these permissions:
- β
**Read** (view datasets)
- β
**Write** (upload results)
- β
**Run Jobs** (submit evaluation jobs)
5. Create and copy the token (starts with `hf_...`)
**β οΈ IMPORTANT Requirements:**
- You must have a **HuggingFace Pro account** ($9/month)
- **Credit card required** to pay for compute usage
- Read-only tokens will NOT work for job submission
- Sign up for Pro: https://huggingface.co/pricing
---
### Modal API Credentials (Optional)
1. Go to [Modal Settings](https://modal.com/settings/tokens)
2. Click "Create new token"
3. Copy both:
- Token ID (starts with `ak-...`)
- Token Secret (starts with `as-...`)
**Why Modal?** Run evaluation jobs on serverless GPU compute with per-second billing.
---
### LLM Provider API Keys (Optional)
These keys enable running evaluations with different model providers:
- **OpenAI**: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
- **Anthropic**: [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)
- **Google (Vertex AI)**: [Google Cloud Console](https://console.cloud.google.com/)
- **Cohere**: [dashboard.cohere.ai/api-keys](https://dashboard.cohere.ai/api-keys)
- **Mistral**: [console.mistral.ai/api-keys](https://console.mistral.ai/api-keys)
- **Together AI**: [api.together.xyz/settings/api-keys](https://api.together.xyz/settings/api-keys)
- **Groq**: [console.groq.com/keys](https://console.groq.com/keys)
Copy and paste them in the `KEY=value` format.
""")
with gr.Accordion("π Privacy & Security", open=False):
gr.Markdown("""
### Your Privacy Matters
- β
**Session-only storage**: API keys are stored only in your browser session
- β
**No server storage**: Keys are never saved to our servers or databases
- β
**HTTPS encryption**: All API calls are made over secure connections
- β
**No logging**: API keys are not logged or tracked
### Best Practices
- π Use dedicated API keys for testing/demos
- π Rotate your keys regularly
- π« Don't share your keys publicly
- π Monitor your API usage on provider dashboards
### Rate Limits
**Gemini API (Free Tier)**:
- 60 requests per minute
- 1,500 requests per day
**HuggingFace**:
- Read access: No strict limits
- Public datasets: Unlimited reads
""")
# Define save functionality
def save_api_keys(gemini_key, hf_key, modal_key, modal_secret, llm_keys_text):
"""Save API keys to session"""
messages = []
# Validate and save Gemini API key
if gemini_key and gemini_key.strip():
if gemini_key.startswith("AIza"):
os.environ["GEMINI_API_KEY"] = gemini_key.strip()
messages.append("β
Gemini API key saved")
gemini_status_text = "β
Configured"
else:
messages.append("β οΈ Invalid Gemini API key format (should start with 'AIza')")
gemini_status_text = "β Invalid format"
else:
gemini_status_text = "βͺ Not configured"
# Validate and save HuggingFace token
if hf_key and hf_key.strip():
if hf_key.startswith("hf_"):
os.environ["HF_TOKEN"] = hf_key.strip()
messages.append("β
HuggingFace token saved")
hf_status_text = "β
Configured"
else:
messages.append("β οΈ Invalid HuggingFace token format (should start with 'hf_')")
hf_status_text = "β Invalid format"
else:
hf_status_text = "βͺ Not configured"
# Validate and save Modal API key
if modal_key and modal_key.strip():
if modal_key.startswith("ak-"):
os.environ["MODAL_TOKEN_ID"] = modal_key.strip()
messages.append("β
Modal API key saved")
modal_status_text = "β
Configured"
else:
messages.append("β οΈ Invalid Modal API key format (should start with 'ak-')")
modal_status_text = "β Invalid format"
else:
modal_status_text = "βͺ Not configured"
# Validate and save Modal API secret
if modal_secret and modal_secret.strip():
if modal_secret.startswith("as-"):
os.environ["MODAL_TOKEN_SECRET"] = modal_secret.strip()
messages.append("β
Modal API secret saved")
modal_secret_status_text = "β
Configured"
else:
messages.append("β οΈ Invalid Modal API secret format (should start with 'as-')")
modal_secret_status_text = "β Invalid format"
else:
modal_secret_status_text = "βͺ Not configured"
# Parse and save LLM provider API keys
llm_keys_count = 0
if llm_keys_text and llm_keys_text.strip():
parsed_keys = _parse_env_string(llm_keys_text)
for key, value in parsed_keys.items():
os.environ[key] = value
llm_keys_count += 1
messages.append(f"β
{llm_keys_count} LLM provider API key(s) saved")
status_msg = "\n\n".join(messages) if messages else "No changes made"
status_msg += "\n\n**Note**: Keys are saved for this session only and will be used for evaluation jobs."
return status_msg, gemini_status_text, hf_status_text, modal_status_text, modal_secret_status_text
def test_api_keys(gemini_key, hf_key, modal_key, modal_secret, llm_keys_text):
"""Test API key connections"""
results = []
# Test Gemini API
if gemini_key and gemini_key.strip():
try:
import google.generativeai as genai
genai.configure(api_key=gemini_key.strip())
# Try to list models as a test
models = list(genai.list_models())
results.append("β
**Gemini API**: Connection successful!")
except Exception as e:
results.append(f"β **Gemini API**: Connection failed - {str(e)}")
else:
results.append("β οΈ **Gemini API**: No key provided")
# Test HuggingFace token
if hf_key and hf_key.strip():
try:
from huggingface_hub import HfApi
api = HfApi(token=hf_key.strip())
# Try to get user info as a test
user_info = api.whoami()
results.append(f"β
**HuggingFace**: Connection successful! (User: {user_info['name']})")
except Exception as e:
results.append(f"β **HuggingFace**: Connection failed - {str(e)}")
else:
results.append("β οΈ **HuggingFace**: No token provided")
# Test Modal API
if modal_key and modal_key.strip() and modal_secret and modal_secret.strip():
try:
import modal
# Modal validates credentials on first use, not at import
# We'll just validate format here
if modal_key.startswith("ak-") and modal_secret.startswith("as-"):
results.append("β
**Modal**: Credentials format valid (will be verified on first job submission)")
else:
results.append("β **Modal**: Invalid credential format")
except Exception as e:
results.append(f"β οΈ **Modal**: {str(e)}")
elif modal_key or modal_secret:
results.append("β οΈ **Modal**: Both API key and secret required")
# Note about LLM provider keys
if llm_keys_text and llm_keys_text.strip():
parsed_keys = _parse_env_string(llm_keys_text)
results.append(f"βΉοΈ **LLM Providers**: {len(parsed_keys)} key(s) configured (will be validated when used)")
return "\n\n".join(results)
# Wire up button events (api_name=False to prevent API key exposure)
save_btn.click(
fn=save_api_keys,
inputs=[gemini_api_key, hf_token, modal_api_key, modal_api_secret, llm_api_keys],
outputs=[status_message, gemini_status, hf_status, modal_status, modal_secret_status],
api_name=False # IMPORTANT: Prevents API key exposure via Gradio API
)
test_btn.click(
fn=test_api_keys,
inputs=[gemini_api_key, hf_token, modal_api_key, modal_api_secret, llm_api_keys],
outputs=[status_message],
api_name=False # IMPORTANT: Prevents API key exposure via Gradio API
)
# Return the interface only (API keys are managed internally via session state)
return settings_interface
if __name__ == "__main__":
# For standalone testing
with gr.Blocks() as demo:
settings_screen = create_settings_screen()
# Make it visible for standalone testing
settings_screen.visible = True
demo.launch()
|