Spaces:
Sleeping
Sleeping
Gemini key input
Browse files- demo/app.py +11 -3
- demo/health.py +12 -8
- demo/setup_cell.py +40 -0
demo/app.py
CHANGED
|
@@ -8,8 +8,8 @@ import health
|
|
| 8 |
from layout import CELL_CSS, cell
|
| 9 |
|
| 10 |
|
| 11 |
-
def render_health_panel() -> str:
|
| 12 |
-
return health.render_health_notice()
|
| 13 |
|
| 14 |
|
| 15 |
def create_app() -> gr.Blocks:
|
|
@@ -58,10 +58,18 @@ Think of this interface as a lightweight Jupyter notebook: instead of code cells
|
|
| 58 |
"""
|
| 59 |
)
|
| 60 |
|
|
|
|
|
|
|
| 61 |
with cell("π©π»ββοΈ Health check"):
|
| 62 |
health_panel = gr.HTML(value=health.render_placeholder_notice())
|
| 63 |
run_button = gr.Button("Run health check", variant="primary")
|
| 64 |
-
run_button.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
return demo
|
| 66 |
|
| 67 |
|
|
|
|
| 8 |
from layout import CELL_CSS, cell
|
| 9 |
|
| 10 |
|
| 11 |
+
def render_health_panel(gemini_api_key: str | None = None) -> str:
|
| 12 |
+
return health.render_health_notice(gemini_api_key)
|
| 13 |
|
| 14 |
|
| 15 |
def create_app() -> gr.Blocks:
|
|
|
|
| 58 |
"""
|
| 59 |
)
|
| 60 |
|
| 61 |
+
gemini_key_box = render_setup_cell()
|
| 62 |
+
|
| 63 |
with cell("π©π»ββοΈ Health check"):
|
| 64 |
health_panel = gr.HTML(value=health.render_placeholder_notice())
|
| 65 |
run_button = gr.Button("Run health check", variant="primary")
|
| 66 |
+
run_button.click(
|
| 67 |
+
fn=render_health_panel,
|
| 68 |
+
inputs=gemini_key_box,
|
| 69 |
+
outputs=health_panel,
|
| 70 |
+
queue=False,
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
return demo
|
| 74 |
|
| 75 |
|
demo/health.py
CHANGED
|
@@ -124,14 +124,16 @@ def _check_ffmpeg() -> ToolStatus:
|
|
| 124 |
return ToolStatus(label, True, first_line)
|
| 125 |
|
| 126 |
|
| 127 |
-
def _check_gemini_env() -> ToolStatus:
|
| 128 |
label = "Gemini API key"
|
| 129 |
-
|
|
|
|
|
|
|
| 130 |
return ToolStatus(label, True, f"{GEMINI_ENV_VAR} is set")
|
| 131 |
return ToolStatus(label, False, f"{GEMINI_ENV_VAR} is not set")
|
| 132 |
|
| 133 |
|
| 134 |
-
def _check_mcp_health() -> ToolStatus:
|
| 135 |
label = "MCP server"
|
| 136 |
try:
|
| 137 |
from fastmcp import Client # type: ignore
|
|
@@ -149,6 +151,8 @@ def _check_mcp_health() -> ToolStatus:
|
|
| 149 |
)
|
| 150 |
env = os.environ.copy()
|
| 151 |
env["PYTHONPATH"] = py_path
|
|
|
|
|
|
|
| 152 |
|
| 153 |
server_entry = ["-m", "aileen3_mcp.server"]
|
| 154 |
|
|
@@ -192,13 +196,13 @@ def _check_mcp_health() -> ToolStatus:
|
|
| 192 |
return asyncio.run(probe())
|
| 193 |
|
| 194 |
|
| 195 |
-
def run_health_report() -> HealthReport:
|
| 196 |
tool_statuses = [
|
| 197 |
_check_deno(),
|
| 198 |
_check_yt_dlp_python(),
|
| 199 |
_check_ffmpeg(),
|
| 200 |
-
_check_gemini_env(),
|
| 201 |
-
_check_mcp_health(),
|
| 202 |
]
|
| 203 |
ok = all(status.ok for status in tool_statuses)
|
| 204 |
if ok:
|
|
@@ -213,8 +217,8 @@ def _sanitize(text: str) -> str:
|
|
| 213 |
return html.escape(text, quote=False)
|
| 214 |
|
| 215 |
|
| 216 |
-
def render_health_notice() -> str:
|
| 217 |
-
report = run_health_report()
|
| 218 |
state_class, icon = ("health-success", "β
") if report.ok else ("health-fail", "π§―")
|
| 219 |
bullet_rows = "".join(
|
| 220 |
f"<li>{'β
' if status.ok else 'β'} {_sanitize(status.label)}: "
|
|
|
|
| 124 |
return ToolStatus(label, True, first_line)
|
| 125 |
|
| 126 |
|
| 127 |
+
def _check_gemini_env(gemini_api_key: str | None = None) -> ToolStatus:
|
| 128 |
label = "Gemini API key"
|
| 129 |
+
# Prefer an explicit key passed from the UI; fall back to process env.
|
| 130 |
+
key = gemini_api_key or os.environ.get(GEMINI_ENV_VAR)
|
| 131 |
+
if key:
|
| 132 |
return ToolStatus(label, True, f"{GEMINI_ENV_VAR} is set")
|
| 133 |
return ToolStatus(label, False, f"{GEMINI_ENV_VAR} is not set")
|
| 134 |
|
| 135 |
|
| 136 |
+
def _check_mcp_health(gemini_api_key: str | None = None) -> ToolStatus:
|
| 137 |
label = "MCP server"
|
| 138 |
try:
|
| 139 |
from fastmcp import Client # type: ignore
|
|
|
|
| 151 |
)
|
| 152 |
env = os.environ.copy()
|
| 153 |
env["PYTHONPATH"] = py_path
|
| 154 |
+
if gemini_api_key:
|
| 155 |
+
env[GEMINI_ENV_VAR] = gemini_api_key
|
| 156 |
|
| 157 |
server_entry = ["-m", "aileen3_mcp.server"]
|
| 158 |
|
|
|
|
| 196 |
return asyncio.run(probe())
|
| 197 |
|
| 198 |
|
| 199 |
+
def run_health_report(gemini_api_key: str | None = None) -> HealthReport:
|
| 200 |
tool_statuses = [
|
| 201 |
_check_deno(),
|
| 202 |
_check_yt_dlp_python(),
|
| 203 |
_check_ffmpeg(),
|
| 204 |
+
_check_gemini_env(gemini_api_key),
|
| 205 |
+
_check_mcp_health(gemini_api_key),
|
| 206 |
]
|
| 207 |
ok = all(status.ok for status in tool_statuses)
|
| 208 |
if ok:
|
|
|
|
| 217 |
return html.escape(text, quote=False)
|
| 218 |
|
| 219 |
|
| 220 |
+
def render_health_notice(gemini_api_key: str | None = None) -> str:
|
| 221 |
+
report = run_health_report(gemini_api_key)
|
| 222 |
state_class, icon = ("health-success", "β
") if report.ok else ("health-fail", "π§―")
|
| 223 |
bullet_rows = "".join(
|
| 224 |
f"<li>{'β
' if status.ok else 'β'} {_sanitize(status.label)}: "
|
demo/setup_cell.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import gradio as gr
|
| 4 |
+
|
| 5 |
+
from layout import cell
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def render_setup_cell() -> gr.Textbox:
|
| 9 |
+
"""
|
| 10 |
+
Render a small setup cell that collects a Gemini API key.
|
| 11 |
+
|
| 12 |
+
The returned textbox component is used by other cells to pass GEMINI_API_KEY
|
| 13 |
+
into the MCP server environment.
|
| 14 |
+
|
| 15 |
+
This is recommended practice for the Gradio/Anthropic hackathon
|
| 16 |
+
"""
|
| 17 |
+
with cell("π Setup: Gemini API key"):
|
| 18 |
+
gr.Markdown(
|
| 19 |
+
"""
|
| 20 |
+
### π Why a Gemini key?
|
| 21 |
+
The Aileen MCP server uses Google Gemini for slide-aware analysis and transcription. To keep the demo lightweight and avoid hard-coding
|
| 22 |
+
credentials, this Space expects you to provide a **Gemini API key** that is scoped to your own Google account or test project.
|
| 23 |
+
|
| 24 |
+
- The key is only used from within this Space to call Gemini via the Aileen MCP server.
|
| 25 |
+
- You can revoke or rotate it at any time in your Google Cloud / AI Studio settings.
|
| 26 |
+
- This respects the time of our esteemed competition reviewers in that they receive a ready-to-run environment. Cautious users may configure
|
| 27 |
+
credentials in config files for the sub components by cloning this space as their own.
|
| 28 |
+
|
| 29 |
+
Enter a key with access to the `gemini-*` family of models. The health check and the demos below will both
|
| 30 |
+
use this value. Note that charges may be incurred, subject to your Gemini access tier.
|
| 31 |
+
"""
|
| 32 |
+
)
|
| 33 |
+
gemini_key_box = gr.Textbox(
|
| 34 |
+
label="Gemini API key",
|
| 35 |
+
type="password",
|
| 36 |
+
placeholder="Paste your Gemini API key here",
|
| 37 |
+
lines=1,
|
| 38 |
+
)
|
| 39 |
+
return gemini_key_box
|
| 40 |
+
|