Spaces:
Running
Running
Commit
Β·
dab7275
1
Parent(s):
a85f4e8
feat: Add Settings screen for API key configuration
Browse files- Create new Settings screen for user-provided API keys (Gemini & HuggingFace)
- Add comprehensive UI with key validation, testing, and usage guides
- Prevent API key exposure via Gradio API using api_name=False
- Add settings navigation button in sidebar
- Update all navigation functions to include settings screen
- Session-only storage for security (no server-side persistence)
- Addresses hackathon judge feedback for credit safety
- app.py +67 -14
- screens/settings.py +214 -0
app.py
CHANGED
|
@@ -60,6 +60,7 @@ from screens.chat import (
|
|
| 60 |
on_quick_action
|
| 61 |
)
|
| 62 |
from screens.documentation import create_documentation_screen
|
|
|
|
| 63 |
from screens.mcp_helpers import (
|
| 64 |
call_analyze_leaderboard_sync,
|
| 65 |
call_debug_trace_sync,
|
|
@@ -1593,6 +1594,7 @@ with gr.Blocks(title="TraceMind-AI", theme=theme) as app:
|
|
| 1593 |
chat_nav_btn = gr.Button("π€ Agent Chat", variant="secondary", size="lg")
|
| 1594 |
synthetic_data_nav_btn = gr.Button("π¬ Synthetic Data", variant="secondary", size="lg")
|
| 1595 |
docs_nav_btn = gr.Button("π Documentation", variant="secondary", size="lg")
|
|
|
|
| 1596 |
|
| 1597 |
gr.Markdown("---")
|
| 1598 |
|
|
@@ -2419,6 +2421,11 @@ with gr.Blocks(title="TraceMind-AI", theme=theme) as app:
|
|
| 2419 |
# ============================================================================
|
| 2420 |
documentation_screen = create_documentation_screen()
|
| 2421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2422 |
# ============================================================================
|
| 2423 |
# Evaluation Helper Functions
|
| 2424 |
# ============================================================================
|
|
@@ -2790,6 +2797,7 @@ No historical data available for **{model}**.
|
|
| 2790 |
synthetic_data_screen: gr.update(visible=False),
|
| 2791 |
new_evaluation_screen: gr.update(visible=False),
|
| 2792 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2793 |
dashboard_nav_btn: gr.update(variant="primary"),
|
| 2794 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2795 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2797,6 +2805,7 @@ No historical data available for **{model}**.
|
|
| 2797 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2798 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2799 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2800 |
}
|
| 2801 |
result.update(dashboard_updates)
|
| 2802 |
return result
|
|
@@ -2813,6 +2822,7 @@ No historical data available for **{model}**.
|
|
| 2813 |
synthetic_data_screen: gr.update(visible=False),
|
| 2814 |
new_evaluation_screen: gr.update(visible=False),
|
| 2815 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2816 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2817 |
leaderboard_nav_btn: gr.update(variant="primary"),
|
| 2818 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2820,6 +2830,7 @@ No historical data available for **{model}**.
|
|
| 2820 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2821 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2822 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2823 |
}
|
| 2824 |
|
| 2825 |
def navigate_to_new_evaluation():
|
|
@@ -2834,6 +2845,7 @@ No historical data available for **{model}**.
|
|
| 2834 |
synthetic_data_screen: gr.update(visible=False),
|
| 2835 |
new_evaluation_screen: gr.update(visible=True),
|
| 2836 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2837 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2838 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2839 |
new_eval_nav_btn: gr.update(variant="primary"),
|
|
@@ -2841,6 +2853,7 @@ No historical data available for **{model}**.
|
|
| 2841 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2842 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2843 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2844 |
}
|
| 2845 |
|
| 2846 |
def navigate_to_compare():
|
|
@@ -2867,6 +2880,7 @@ No historical data available for **{model}**.
|
|
| 2867 |
synthetic_data_screen: gr.update(visible=False),
|
| 2868 |
new_evaluation_screen: gr.update(visible=False),
|
| 2869 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2870 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2871 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2872 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2896,6 +2910,7 @@ No historical data available for **{model}**.
|
|
| 2896 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2897 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2898 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2899 |
}
|
| 2900 |
|
| 2901 |
def navigate_to_chat():
|
|
@@ -2910,6 +2925,7 @@ No historical data available for **{model}**.
|
|
| 2910 |
synthetic_data_screen: gr.update(visible=False),
|
| 2911 |
new_evaluation_screen: gr.update(visible=False),
|
| 2912 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2913 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2914 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2915 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2917,6 +2933,7 @@ No historical data available for **{model}**.
|
|
| 2917 |
chat_nav_btn: gr.update(variant="primary"),
|
| 2918 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2919 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2920 |
}
|
| 2921 |
|
| 2922 |
def navigate_to_synthetic_data():
|
|
@@ -2931,6 +2948,7 @@ No historical data available for **{model}**.
|
|
| 2931 |
synthetic_data_screen: gr.update(visible=True),
|
| 2932 |
new_evaluation_screen: gr.update(visible=False),
|
| 2933 |
documentation_screen: gr.update(visible=False),
|
|
|
|
| 2934 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2935 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2936 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2938,6 +2956,7 @@ No historical data available for **{model}**.
|
|
| 2938 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2939 |
synthetic_data_nav_btn: gr.update(variant="primary"),
|
| 2940 |
docs_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2941 |
}
|
| 2942 |
|
| 2943 |
def navigate_to_documentation():
|
|
@@ -2952,6 +2971,7 @@ No historical data available for **{model}**.
|
|
| 2952 |
synthetic_data_screen: gr.update(visible=False),
|
| 2953 |
new_evaluation_screen: gr.update(visible=False),
|
| 2954 |
documentation_screen: gr.update(visible=True),
|
|
|
|
| 2955 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2956 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2957 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
@@ -2959,6 +2979,30 @@ No historical data available for **{model}**.
|
|
| 2959 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2960 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2961 |
docs_nav_btn: gr.update(variant="primary"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2962 |
}
|
| 2963 |
|
| 2964 |
# Synthetic Data Generator Callbacks
|
|
@@ -3277,24 +3321,24 @@ Result: {result}
|
|
| 3277 |
fn=navigate_to_dashboard,
|
| 3278 |
outputs=[
|
| 3279 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3280 |
-
new_evaluation_screen, documentation_screen,
|
| 3281 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3282 |
] + list(dashboard_components.values())
|
| 3283 |
)
|
| 3284 |
|
| 3285 |
leaderboard_nav_btn.click(
|
| 3286 |
fn=navigate_to_leaderboard,
|
| 3287 |
outputs=[
|
| 3288 |
-
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen,
|
| 3289 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3290 |
]
|
| 3291 |
)
|
| 3292 |
|
| 3293 |
new_eval_nav_btn.click(
|
| 3294 |
fn=navigate_to_new_evaluation,
|
| 3295 |
outputs=[
|
| 3296 |
-
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen,
|
| 3297 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3298 |
]
|
| 3299 |
)
|
| 3300 |
|
|
@@ -3302,7 +3346,7 @@ Result: {result}
|
|
| 3302 |
fn=navigate_to_compare,
|
| 3303 |
outputs=[
|
| 3304 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3305 |
-
new_evaluation_screen, documentation_screen,
|
| 3306 |
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn,
|
| 3307 |
compare_components['compare_run_a_dropdown'], compare_components['compare_run_b_dropdown']
|
| 3308 |
]
|
|
@@ -3312,16 +3356,16 @@ Result: {result}
|
|
| 3312 |
fn=navigate_to_chat,
|
| 3313 |
outputs=[
|
| 3314 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3315 |
-
new_evaluation_screen, documentation_screen,
|
| 3316 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3317 |
]
|
| 3318 |
)
|
| 3319 |
synthetic_data_nav_btn.click(
|
| 3320 |
fn=navigate_to_synthetic_data,
|
| 3321 |
outputs=[
|
| 3322 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3323 |
-
new_evaluation_screen, documentation_screen,
|
| 3324 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3325 |
]
|
| 3326 |
)
|
| 3327 |
|
|
@@ -3329,8 +3373,17 @@ Result: {result}
|
|
| 3329 |
fn=navigate_to_documentation,
|
| 3330 |
outputs=[
|
| 3331 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3332 |
-
new_evaluation_screen, documentation_screen,
|
| 3333 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3334 |
]
|
| 3335 |
)
|
| 3336 |
|
|
@@ -3352,7 +3405,7 @@ Result: {result}
|
|
| 3352 |
fn=navigate_to_leaderboard,
|
| 3353 |
outputs=[
|
| 3354 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen,
|
| 3355 |
-
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn
|
| 3356 |
]
|
| 3357 |
)
|
| 3358 |
|
|
|
|
| 60 |
on_quick_action
|
| 61 |
)
|
| 62 |
from screens.documentation import create_documentation_screen
|
| 63 |
+
from screens.settings import create_settings_screen
|
| 64 |
from screens.mcp_helpers import (
|
| 65 |
call_analyze_leaderboard_sync,
|
| 66 |
call_debug_trace_sync,
|
|
|
|
| 1594 |
chat_nav_btn = gr.Button("π€ Agent Chat", variant="secondary", size="lg")
|
| 1595 |
synthetic_data_nav_btn = gr.Button("π¬ Synthetic Data", variant="secondary", size="lg")
|
| 1596 |
docs_nav_btn = gr.Button("π Documentation", variant="secondary", size="lg")
|
| 1597 |
+
settings_nav_btn = gr.Button("βοΈ Settings", variant="secondary", size="lg")
|
| 1598 |
|
| 1599 |
gr.Markdown("---")
|
| 1600 |
|
|
|
|
| 2421 |
# ============================================================================
|
| 2422 |
documentation_screen = create_documentation_screen()
|
| 2423 |
|
| 2424 |
+
# ============================================================================
|
| 2425 |
+
# Screen 10: Settings
|
| 2426 |
+
# ============================================================================
|
| 2427 |
+
settings_screen, gemini_api_key_input, hf_token_input = create_settings_screen()
|
| 2428 |
+
|
| 2429 |
# ============================================================================
|
| 2430 |
# Evaluation Helper Functions
|
| 2431 |
# ============================================================================
|
|
|
|
| 2797 |
synthetic_data_screen: gr.update(visible=False),
|
| 2798 |
new_evaluation_screen: gr.update(visible=False),
|
| 2799 |
documentation_screen: gr.update(visible=False),
|
| 2800 |
+
settings_screen: gr.update(visible=False),
|
| 2801 |
dashboard_nav_btn: gr.update(variant="primary"),
|
| 2802 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2803 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2805 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2806 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2807 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2808 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2809 |
}
|
| 2810 |
result.update(dashboard_updates)
|
| 2811 |
return result
|
|
|
|
| 2822 |
synthetic_data_screen: gr.update(visible=False),
|
| 2823 |
new_evaluation_screen: gr.update(visible=False),
|
| 2824 |
documentation_screen: gr.update(visible=False),
|
| 2825 |
+
settings_screen: gr.update(visible=False),
|
| 2826 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2827 |
leaderboard_nav_btn: gr.update(variant="primary"),
|
| 2828 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2830 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2831 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2832 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2833 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2834 |
}
|
| 2835 |
|
| 2836 |
def navigate_to_new_evaluation():
|
|
|
|
| 2845 |
synthetic_data_screen: gr.update(visible=False),
|
| 2846 |
new_evaluation_screen: gr.update(visible=True),
|
| 2847 |
documentation_screen: gr.update(visible=False),
|
| 2848 |
+
settings_screen: gr.update(visible=False),
|
| 2849 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2850 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2851 |
new_eval_nav_btn: gr.update(variant="primary"),
|
|
|
|
| 2853 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2854 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2855 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2856 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2857 |
}
|
| 2858 |
|
| 2859 |
def navigate_to_compare():
|
|
|
|
| 2880 |
synthetic_data_screen: gr.update(visible=False),
|
| 2881 |
new_evaluation_screen: gr.update(visible=False),
|
| 2882 |
documentation_screen: gr.update(visible=False),
|
| 2883 |
+
settings_screen: gr.update(visible=False),
|
| 2884 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2885 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2886 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2910 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2911 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2912 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2913 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2914 |
}
|
| 2915 |
|
| 2916 |
def navigate_to_chat():
|
|
|
|
| 2925 |
synthetic_data_screen: gr.update(visible=False),
|
| 2926 |
new_evaluation_screen: gr.update(visible=False),
|
| 2927 |
documentation_screen: gr.update(visible=False),
|
| 2928 |
+
settings_screen: gr.update(visible=False),
|
| 2929 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2930 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2931 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2933 |
chat_nav_btn: gr.update(variant="primary"),
|
| 2934 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2935 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2936 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2937 |
}
|
| 2938 |
|
| 2939 |
def navigate_to_synthetic_data():
|
|
|
|
| 2948 |
synthetic_data_screen: gr.update(visible=True),
|
| 2949 |
new_evaluation_screen: gr.update(visible=False),
|
| 2950 |
documentation_screen: gr.update(visible=False),
|
| 2951 |
+
settings_screen: gr.update(visible=False),
|
| 2952 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2953 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2954 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2956 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2957 |
synthetic_data_nav_btn: gr.update(variant="primary"),
|
| 2958 |
docs_nav_btn: gr.update(variant="secondary"),
|
| 2959 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2960 |
}
|
| 2961 |
|
| 2962 |
def navigate_to_documentation():
|
|
|
|
| 2971 |
synthetic_data_screen: gr.update(visible=False),
|
| 2972 |
new_evaluation_screen: gr.update(visible=False),
|
| 2973 |
documentation_screen: gr.update(visible=True),
|
| 2974 |
+
settings_screen: gr.update(visible=False),
|
| 2975 |
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2976 |
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 2977 |
new_eval_nav_btn: gr.update(variant="secondary"),
|
|
|
|
| 2979 |
chat_nav_btn: gr.update(variant="secondary"),
|
| 2980 |
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 2981 |
docs_nav_btn: gr.update(variant="primary"),
|
| 2982 |
+
settings_nav_btn: gr.update(variant="secondary"),
|
| 2983 |
+
}
|
| 2984 |
+
|
| 2985 |
+
def navigate_to_settings():
|
| 2986 |
+
"""Navigate to settings screen"""
|
| 2987 |
+
return {
|
| 2988 |
+
dashboard_screen: gr.update(visible=False),
|
| 2989 |
+
leaderboard_screen: gr.update(visible=False),
|
| 2990 |
+
run_detail_screen: gr.update(visible=False),
|
| 2991 |
+
trace_detail_screen: gr.update(visible=False),
|
| 2992 |
+
compare_screen: gr.update(visible=False),
|
| 2993 |
+
chat_screen: gr.update(visible=False),
|
| 2994 |
+
synthetic_data_screen: gr.update(visible=False),
|
| 2995 |
+
new_evaluation_screen: gr.update(visible=False),
|
| 2996 |
+
documentation_screen: gr.update(visible=False),
|
| 2997 |
+
settings_screen: gr.update(visible=True),
|
| 2998 |
+
dashboard_nav_btn: gr.update(variant="secondary"),
|
| 2999 |
+
leaderboard_nav_btn: gr.update(variant="secondary"),
|
| 3000 |
+
new_eval_nav_btn: gr.update(variant="secondary"),
|
| 3001 |
+
compare_nav_btn: gr.update(variant="secondary"),
|
| 3002 |
+
chat_nav_btn: gr.update(variant="secondary"),
|
| 3003 |
+
synthetic_data_nav_btn: gr.update(variant="secondary"),
|
| 3004 |
+
docs_nav_btn: gr.update(variant="secondary"),
|
| 3005 |
+
settings_nav_btn: gr.update(variant="primary"),
|
| 3006 |
}
|
| 3007 |
|
| 3008 |
# Synthetic Data Generator Callbacks
|
|
|
|
| 3321 |
fn=navigate_to_dashboard,
|
| 3322 |
outputs=[
|
| 3323 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3324 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3325 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3326 |
] + list(dashboard_components.values())
|
| 3327 |
)
|
| 3328 |
|
| 3329 |
leaderboard_nav_btn.click(
|
| 3330 |
fn=navigate_to_leaderboard,
|
| 3331 |
outputs=[
|
| 3332 |
+
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen, settings_screen,
|
| 3333 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3334 |
]
|
| 3335 |
)
|
| 3336 |
|
| 3337 |
new_eval_nav_btn.click(
|
| 3338 |
fn=navigate_to_new_evaluation,
|
| 3339 |
outputs=[
|
| 3340 |
+
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen, settings_screen,
|
| 3341 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3342 |
]
|
| 3343 |
)
|
| 3344 |
|
|
|
|
| 3346 |
fn=navigate_to_compare,
|
| 3347 |
outputs=[
|
| 3348 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3349 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3350 |
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn,
|
| 3351 |
compare_components['compare_run_a_dropdown'], compare_components['compare_run_b_dropdown']
|
| 3352 |
]
|
|
|
|
| 3356 |
fn=navigate_to_chat,
|
| 3357 |
outputs=[
|
| 3358 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3359 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3360 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3361 |
]
|
| 3362 |
)
|
| 3363 |
synthetic_data_nav_btn.click(
|
| 3364 |
fn=navigate_to_synthetic_data,
|
| 3365 |
outputs=[
|
| 3366 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3367 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3368 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3369 |
]
|
| 3370 |
)
|
| 3371 |
|
|
|
|
| 3373 |
fn=navigate_to_documentation,
|
| 3374 |
outputs=[
|
| 3375 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3376 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3377 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3378 |
+
]
|
| 3379 |
+
)
|
| 3380 |
+
|
| 3381 |
+
settings_nav_btn.click(
|
| 3382 |
+
fn=navigate_to_settings,
|
| 3383 |
+
outputs=[
|
| 3384 |
+
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen,
|
| 3385 |
+
new_evaluation_screen, documentation_screen, settings_screen,
|
| 3386 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3387 |
]
|
| 3388 |
)
|
| 3389 |
|
|
|
|
| 3405 |
fn=navigate_to_leaderboard,
|
| 3406 |
outputs=[
|
| 3407 |
dashboard_screen, leaderboard_screen, run_detail_screen, trace_detail_screen, compare_screen, chat_screen, synthetic_data_screen, new_evaluation_screen, documentation_screen,
|
| 3408 |
+
dashboard_nav_btn, leaderboard_nav_btn, new_eval_nav_btn, compare_nav_btn, chat_nav_btn, synthetic_data_nav_btn, docs_nav_btn, settings_nav_btn
|
| 3409 |
]
|
| 3410 |
)
|
| 3411 |
|
screens/settings.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Settings Screen for TraceMind-AI
|
| 3 |
+
Allows users to configure API keys for Gemini and HuggingFace
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import gradio as gr
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def create_settings_screen():
|
| 11 |
+
"""
|
| 12 |
+
Create the settings screen for API key configuration
|
| 13 |
+
|
| 14 |
+
Returns:
|
| 15 |
+
gr.Column: Gradio Column component for settings (can be shown/hidden)
|
| 16 |
+
"""
|
| 17 |
+
with gr.Column(visible=False) as settings_interface:
|
| 18 |
+
gr.Markdown("""
|
| 19 |
+
# βοΈ Settings
|
| 20 |
+
|
| 21 |
+
Configure your API keys to use TraceMind features. These keys are stored only in your browser session and are never saved to our servers.
|
| 22 |
+
""")
|
| 23 |
+
|
| 24 |
+
with gr.Accordion("π API Key Configuration", open=True):
|
| 25 |
+
gr.Markdown("""
|
| 26 |
+
### Why provide API keys?
|
| 27 |
+
|
| 28 |
+
TraceMind uses external services to provide intelligent analysis and insights:
|
| 29 |
+
- **Google Gemini API**: Powers the MCP server for leaderboard analysis, cost estimation, and trace debugging
|
| 30 |
+
- **HuggingFace Token**: Required to access evaluation datasets and results
|
| 31 |
+
|
| 32 |
+
**For Judges & Visitors**: Please enter your own API keys to prevent credit issues during evaluation.
|
| 33 |
+
""")
|
| 34 |
+
|
| 35 |
+
# Gemini API Key
|
| 36 |
+
with gr.Row():
|
| 37 |
+
with gr.Column(scale=4):
|
| 38 |
+
gemini_api_key = gr.Textbox(
|
| 39 |
+
label="Google Gemini API Key",
|
| 40 |
+
placeholder="Enter your Gemini API key (starts with 'AIza...')",
|
| 41 |
+
type="password",
|
| 42 |
+
value=os.environ.get("GEMINI_API_KEY", ""),
|
| 43 |
+
info="Get your free API key at: https://ai.google.dev/"
|
| 44 |
+
)
|
| 45 |
+
with gr.Column(scale=1):
|
| 46 |
+
gemini_status = gr.Markdown("βͺ Not configured")
|
| 47 |
+
|
| 48 |
+
# HuggingFace Token
|
| 49 |
+
with gr.Row():
|
| 50 |
+
with gr.Column(scale=4):
|
| 51 |
+
hf_token = gr.Textbox(
|
| 52 |
+
label="HuggingFace Token",
|
| 53 |
+
placeholder="Enter your HF token (starts with 'hf_...')",
|
| 54 |
+
type="password",
|
| 55 |
+
value=os.environ.get("HF_TOKEN", ""),
|
| 56 |
+
info="Get your token at: https://huggingface.co/settings/tokens"
|
| 57 |
+
)
|
| 58 |
+
with gr.Column(scale=1):
|
| 59 |
+
hf_status = gr.Markdown("βͺ Not configured")
|
| 60 |
+
|
| 61 |
+
# Save button
|
| 62 |
+
with gr.Row():
|
| 63 |
+
save_btn = gr.Button("πΎ Save API Keys", variant="primary")
|
| 64 |
+
test_btn = gr.Button("π§ͺ Test Connection", variant="secondary")
|
| 65 |
+
|
| 66 |
+
# Status message
|
| 67 |
+
status_message = gr.Markdown("")
|
| 68 |
+
|
| 69 |
+
with gr.Accordion("π How to Get API Keys", open=False):
|
| 70 |
+
gr.Markdown("""
|
| 71 |
+
### Google Gemini API Key
|
| 72 |
+
|
| 73 |
+
1. Go to [Google AI Studio](https://ai.google.dev/)
|
| 74 |
+
2. Click "Get API Key" in the top right
|
| 75 |
+
3. Create a new project or select an existing one
|
| 76 |
+
4. Generate an API key
|
| 77 |
+
5. Copy the key (starts with `AIza...`)
|
| 78 |
+
|
| 79 |
+
**Free Tier**: 60 requests per minute, suitable for testing and demos
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
### HuggingFace Token
|
| 84 |
+
|
| 85 |
+
1. Go to [HuggingFace Settings](https://huggingface.co/settings/tokens)
|
| 86 |
+
2. Click "New token"
|
| 87 |
+
3. Give it a name (e.g., "TraceMind Access")
|
| 88 |
+
4. Select "Read" permissions
|
| 89 |
+
5. Create and copy the token (starts with `hf_...`)
|
| 90 |
+
|
| 91 |
+
**Note**: Read-only access is sufficient for viewing datasets
|
| 92 |
+
""")
|
| 93 |
+
|
| 94 |
+
with gr.Accordion("π Privacy & Security", open=False):
|
| 95 |
+
gr.Markdown("""
|
| 96 |
+
### Your Privacy Matters
|
| 97 |
+
|
| 98 |
+
- β
**Session-only storage**: API keys are stored only in your browser session
|
| 99 |
+
- β
**No server storage**: Keys are never saved to our servers or databases
|
| 100 |
+
- β
**HTTPS encryption**: All API calls are made over secure connections
|
| 101 |
+
- β
**No logging**: API keys are not logged or tracked
|
| 102 |
+
|
| 103 |
+
### Best Practices
|
| 104 |
+
|
| 105 |
+
- π Use dedicated API keys for testing/demos
|
| 106 |
+
- π Rotate your keys regularly
|
| 107 |
+
- π« Don't share your keys publicly
|
| 108 |
+
- π Monitor your API usage on provider dashboards
|
| 109 |
+
|
| 110 |
+
### Rate Limits
|
| 111 |
+
|
| 112 |
+
**Gemini API (Free Tier)**:
|
| 113 |
+
- 60 requests per minute
|
| 114 |
+
- 1,500 requests per day
|
| 115 |
+
|
| 116 |
+
**HuggingFace**:
|
| 117 |
+
- Read access: No strict limits
|
| 118 |
+
- Public datasets: Unlimited reads
|
| 119 |
+
""")
|
| 120 |
+
|
| 121 |
+
# Define save functionality
|
| 122 |
+
def save_api_keys(gemini_key, hf_key):
|
| 123 |
+
"""Save API keys to session"""
|
| 124 |
+
messages = []
|
| 125 |
+
|
| 126 |
+
# Validate and save Gemini API key
|
| 127 |
+
if gemini_key and gemini_key.strip():
|
| 128 |
+
if gemini_key.startswith("AIza"):
|
| 129 |
+
os.environ["GEMINI_API_KEY"] = gemini_key.strip()
|
| 130 |
+
messages.append("β
Gemini API key saved")
|
| 131 |
+
gemini_status_text = "β
Configured"
|
| 132 |
+
else:
|
| 133 |
+
messages.append("β οΈ Invalid Gemini API key format (should start with 'AIza')")
|
| 134 |
+
gemini_status_text = "β Invalid format"
|
| 135 |
+
else:
|
| 136 |
+
messages.append("β οΈ Gemini API key not provided")
|
| 137 |
+
gemini_status_text = "βͺ Not configured"
|
| 138 |
+
|
| 139 |
+
# Validate and save HuggingFace token
|
| 140 |
+
if hf_key and hf_key.strip():
|
| 141 |
+
if hf_key.startswith("hf_"):
|
| 142 |
+
os.environ["HF_TOKEN"] = hf_key.strip()
|
| 143 |
+
messages.append("β
HuggingFace token saved")
|
| 144 |
+
hf_status_text = "β
Configured"
|
| 145 |
+
else:
|
| 146 |
+
messages.append("β οΈ Invalid HuggingFace token format (should start with 'hf_')")
|
| 147 |
+
hf_status_text = "β Invalid format"
|
| 148 |
+
else:
|
| 149 |
+
messages.append("β οΈ HuggingFace token not provided")
|
| 150 |
+
hf_status_text = "βͺ Not configured"
|
| 151 |
+
|
| 152 |
+
status_msg = "\n\n".join(messages)
|
| 153 |
+
status_msg += "\n\n**Note**: Keys are saved for this session only and will be used for MCP server calls."
|
| 154 |
+
|
| 155 |
+
return status_msg, gemini_status_text, hf_status_text
|
| 156 |
+
|
| 157 |
+
def test_api_keys(gemini_key, hf_key):
|
| 158 |
+
"""Test API key connections"""
|
| 159 |
+
results = []
|
| 160 |
+
|
| 161 |
+
# Test Gemini API
|
| 162 |
+
if gemini_key and gemini_key.strip():
|
| 163 |
+
try:
|
| 164 |
+
import google.generativeai as genai
|
| 165 |
+
genai.configure(api_key=gemini_key.strip())
|
| 166 |
+
# Try to list models as a test
|
| 167 |
+
models = genai.list_models()
|
| 168 |
+
results.append("β
**Gemini API**: Connection successful!")
|
| 169 |
+
except Exception as e:
|
| 170 |
+
results.append(f"β **Gemini API**: Connection failed - {str(e)}")
|
| 171 |
+
else:
|
| 172 |
+
results.append("β οΈ **Gemini API**: No key provided")
|
| 173 |
+
|
| 174 |
+
# Test HuggingFace token
|
| 175 |
+
if hf_key and hf_key.strip():
|
| 176 |
+
try:
|
| 177 |
+
from huggingface_hub import HfApi
|
| 178 |
+
api = HfApi(token=hf_key.strip())
|
| 179 |
+
# Try to get user info as a test
|
| 180 |
+
user_info = api.whoami()
|
| 181 |
+
results.append(f"β
**HuggingFace**: Connection successful! (User: {user_info['name']})")
|
| 182 |
+
except Exception as e:
|
| 183 |
+
results.append(f"β **HuggingFace**: Connection failed - {str(e)}")
|
| 184 |
+
else:
|
| 185 |
+
results.append("β οΈ **HuggingFace**: No token provided")
|
| 186 |
+
|
| 187 |
+
return "\n\n".join(results)
|
| 188 |
+
|
| 189 |
+
# Wire up button events (api_name=False to prevent API key exposure)
|
| 190 |
+
save_btn.click(
|
| 191 |
+
fn=save_api_keys,
|
| 192 |
+
inputs=[gemini_api_key, hf_token],
|
| 193 |
+
outputs=[status_message, gemini_status, hf_status],
|
| 194 |
+
api_name=False # IMPORTANT: Prevents API key exposure via Gradio API
|
| 195 |
+
)
|
| 196 |
+
|
| 197 |
+
test_btn.click(
|
| 198 |
+
fn=test_api_keys,
|
| 199 |
+
inputs=[gemini_api_key, hf_token],
|
| 200 |
+
outputs=[status_message],
|
| 201 |
+
api_name=False # IMPORTANT: Prevents API key exposure via Gradio API
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
# Return both the interface and the input components for external access
|
| 205 |
+
return settings_interface, gemini_api_key, hf_token
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
if __name__ == "__main__":
|
| 209 |
+
# For standalone testing
|
| 210 |
+
with gr.Blocks() as demo:
|
| 211 |
+
settings_screen, _, _ = create_settings_screen()
|
| 212 |
+
# Make it visible for standalone testing
|
| 213 |
+
settings_screen.visible = True
|
| 214 |
+
demo.launch()
|