added secret logic
Browse files- adapters/external/part1_runner.py +12 -7
- adapters/external/part2_runner.py +13 -6
- app/ui.py +2 -2
- core/config.py +13 -3
- utils/env.py +1 -1
adapters/external/part1_runner.py
CHANGED
|
@@ -2,23 +2,28 @@ from typing import Optional
|
|
| 2 |
from pathlib import Path
|
| 3 |
import logging
|
| 4 |
from inspect import signature
|
| 5 |
-
from vendors.part1.main import run_ielts_part1_agent
|
| 6 |
from utils.env import temp_env
|
| 7 |
|
| 8 |
logger = logging.getLogger(__name__)
|
| 9 |
|
| 10 |
def run_part1(image_path: str | Path, essay_text: str, api_key: Optional[str] = None) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
image_path = Path(image_path)
|
| 12 |
if not image_path.exists():
|
| 13 |
raise FileNotFoundError(f"Image not found: {image_path}")
|
| 14 |
|
| 15 |
logger.info("Running Part1 agent")
|
| 16 |
|
| 17 |
-
try:
|
| 18 |
-
if "api_key" in signature(run_ielts_part1_agent).parameters and api_key:
|
| 19 |
-
return str(run_ielts_part1_agent(str(image_path), essay_text, api_key=api_key))
|
| 20 |
-
except Exception:
|
| 21 |
-
pass
|
| 22 |
-
|
| 23 |
with temp_env("GOOGLE_API_KEY", api_key):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
return str(run_ielts_part1_agent(str(image_path), essay_text))
|
|
|
|
| 2 |
from pathlib import Path
|
| 3 |
import logging
|
| 4 |
from inspect import signature
|
|
|
|
| 5 |
from utils.env import temp_env
|
| 6 |
|
| 7 |
logger = logging.getLogger(__name__)
|
| 8 |
|
| 9 |
def run_part1(image_path: str | Path, essay_text: str, api_key: Optional[str] = None) -> str:
|
| 10 |
+
"""
|
| 11 |
+
Lazy-import vendor code AFTER we inject GOOGLE_API_KEY so that any
|
| 12 |
+
model constructed at import time sees the key.
|
| 13 |
+
"""
|
| 14 |
image_path = Path(image_path)
|
| 15 |
if not image_path.exists():
|
| 16 |
raise FileNotFoundError(f"Image not found: {image_path}")
|
| 17 |
|
| 18 |
logger.info("Running Part1 agent")
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
with temp_env("GOOGLE_API_KEY", api_key):
|
| 21 |
+
from vendors.part1.main import run_ielts_part1_agent
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
if "api_key" in signature(run_ielts_part1_agent).parameters and api_key:
|
| 25 |
+
return str(run_ielts_part1_agent(str(image_path), essay_text, api_key=api_key))
|
| 26 |
+
except Exception:
|
| 27 |
+
pass
|
| 28 |
+
|
| 29 |
return str(run_ielts_part1_agent(str(image_path), essay_text))
|
adapters/external/part2_runner.py
CHANGED
|
@@ -1,17 +1,24 @@
|
|
| 1 |
import logging
|
| 2 |
from inspect import signature
|
| 3 |
from typing import Optional
|
| 4 |
-
from vendors.part2.main import run_ielts_part2_agent
|
| 5 |
from utils.env import temp_env
|
| 6 |
|
| 7 |
logger = logging.getLogger(__name__)
|
| 8 |
|
| 9 |
def run_part2(question: str, essay_text: str, api_key: Optional[str] = None) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
logger.info("Running Part2 agent")
|
| 11 |
-
|
| 12 |
-
if "api_key" in signature(run_ielts_part2_agent).parameters and api_key:
|
| 13 |
-
return str(run_ielts_part2_agent(question, essay_text, api_key=api_key))
|
| 14 |
-
except Exception:
|
| 15 |
-
pass
|
| 16 |
with temp_env("GOOGLE_API_KEY", api_key):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
return str(run_ielts_part2_agent(question, essay_text))
|
|
|
|
| 1 |
import logging
|
| 2 |
from inspect import signature
|
| 3 |
from typing import Optional
|
|
|
|
| 4 |
from utils.env import temp_env
|
| 5 |
|
| 6 |
logger = logging.getLogger(__name__)
|
| 7 |
|
| 8 |
def run_part2(question: str, essay_text: str, api_key: Optional[str] = None) -> str:
|
| 9 |
+
"""
|
| 10 |
+
Same lazy-import pattern as Part1; ensures import-time model build
|
| 11 |
+
sees GOOGLE_API_KEY when running on Spaces with BYO key.
|
| 12 |
+
"""
|
| 13 |
logger.info("Running Part2 agent")
|
| 14 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
with temp_env("GOOGLE_API_KEY", api_key):
|
| 16 |
+
from vendors.part2.main import run_ielts_part2_agent
|
| 17 |
+
|
| 18 |
+
try:
|
| 19 |
+
if "api_key" in signature(run_ielts_part2_agent).parameters and api_key:
|
| 20 |
+
return str(run_ielts_part2_agent(question, essay_text, api_key=api_key))
|
| 21 |
+
except Exception:
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
return str(run_ielts_part2_agent(question, essay_text))
|
app/ui.py
CHANGED
|
@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
|
|
| 11 |
session_key = gr.State("")
|
| 12 |
|
| 13 |
def _effective_key(user_input_key: str | None) -> str | None:
|
| 14 |
-
"""Priority: user input (session) > env (local or Space Secret)."""
|
| 15 |
k = (user_input_key or "").strip()
|
| 16 |
if k:
|
| 17 |
return k
|
|
@@ -73,7 +73,7 @@ with gr.Blocks(title="IELTS Writing Assistant", fill_height=True) as demo:
|
|
| 73 |
gr.Markdown(
|
| 74 |
f"Set your API key. Locally, you can save to `.env`. On Spaces, use **Session Key** or set a **Space Secret** `{ENV_VAR_NAME}`."
|
| 75 |
)
|
| 76 |
-
key_box = gr.Textbox(label=f"{ENV_VAR_NAME}", type="password", placeholder="
|
| 77 |
save_local = gr.Button("Save to .env (Local Only)")
|
| 78 |
save_session = gr.Button("Save Session Key")
|
| 79 |
status = gr.Markdown("")
|
|
|
|
| 11 |
session_key = gr.State("")
|
| 12 |
|
| 13 |
def _effective_key(user_input_key: str | None) -> str | None:
|
| 14 |
+
"""Priority: user input (session) > env (local .env or Space Secret)."""
|
| 15 |
k = (user_input_key or "").strip()
|
| 16 |
if k:
|
| 17 |
return k
|
|
|
|
| 73 |
gr.Markdown(
|
| 74 |
f"Set your API key. Locally, you can save to `.env`. On Spaces, use **Session Key** or set a **Space Secret** `{ENV_VAR_NAME}`."
|
| 75 |
)
|
| 76 |
+
key_box = gr.Textbox(label=f"{ENV_VAR_NAME}", type="password", placeholder="AIza... (your Google API key)")
|
| 77 |
save_local = gr.Button("Save to .env (Local Only)")
|
| 78 |
save_session = gr.Button("Save Session Key")
|
| 79 |
status = gr.Markdown("")
|
core/config.py
CHANGED
|
@@ -3,14 +3,17 @@ from pathlib import Path
|
|
| 3 |
from dotenv import load_dotenv
|
| 4 |
|
| 5 |
ENV_PATH = Path(".env")
|
| 6 |
-
ENV_VAR_NAME = "GOOGLE_API_KEY"
|
| 7 |
|
|
|
|
| 8 |
load_dotenv(dotenv_path=ENV_PATH, override=False)
|
| 9 |
|
| 10 |
def in_hf_spaces() -> bool:
|
|
|
|
| 11 |
return bool(os.getenv("SPACE_ID"))
|
| 12 |
|
| 13 |
def get_api_key() -> str | None:
|
|
|
|
| 14 |
return os.getenv(ENV_VAR_NAME)
|
| 15 |
|
| 16 |
def ensure_env_file() -> None:
|
|
@@ -18,10 +21,16 @@ def ensure_env_file() -> None:
|
|
| 18 |
ENV_PATH.write_text("")
|
| 19 |
|
| 20 |
def set_api_key(value: str, var_name: str = ENV_VAR_NAME) -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
if in_hf_spaces():
|
| 22 |
-
return
|
|
|
|
| 23 |
value = (value or "").strip()
|
| 24 |
ensure_env_file()
|
|
|
|
| 25 |
lines = ENV_PATH.read_text().splitlines()
|
| 26 |
out, found = [], False
|
| 27 |
for line in lines:
|
|
@@ -32,5 +41,6 @@ def set_api_key(value: str, var_name: str = ENV_VAR_NAME) -> None:
|
|
| 32 |
out.append(line)
|
| 33 |
if not found:
|
| 34 |
out.append(f"{var_name}={value}")
|
|
|
|
| 35 |
ENV_PATH.write_text("\n".join(out) + "\n")
|
| 36 |
-
os.environ[var_name] = value
|
|
|
|
| 3 |
from dotenv import load_dotenv
|
| 4 |
|
| 5 |
ENV_PATH = Path(".env")
|
| 6 |
+
ENV_VAR_NAME = "GOOGLE_API_KEY" # Keep Google-style key name for Gemini
|
| 7 |
|
| 8 |
+
# Load .env once on import (local runs)
|
| 9 |
load_dotenv(dotenv_path=ENV_PATH, override=False)
|
| 10 |
|
| 11 |
def in_hf_spaces() -> bool:
|
| 12 |
+
"""Detect if running inside Hugging Face Spaces."""
|
| 13 |
return bool(os.getenv("SPACE_ID"))
|
| 14 |
|
| 15 |
def get_api_key() -> str | None:
|
| 16 |
+
"""Read the API key (from env or Space Secret)."""
|
| 17 |
return os.getenv(ENV_VAR_NAME)
|
| 18 |
|
| 19 |
def ensure_env_file() -> None:
|
|
|
|
| 21 |
ENV_PATH.write_text("")
|
| 22 |
|
| 23 |
def set_api_key(value: str, var_name: str = ENV_VAR_NAME) -> None:
|
| 24 |
+
"""
|
| 25 |
+
Persist the key to .env for local runs.
|
| 26 |
+
On Spaces, DO NOT write to disk (no-op) — use session key instead.
|
| 27 |
+
"""
|
| 28 |
if in_hf_spaces():
|
| 29 |
+
return # no-op on Spaces
|
| 30 |
+
|
| 31 |
value = (value or "").strip()
|
| 32 |
ensure_env_file()
|
| 33 |
+
|
| 34 |
lines = ENV_PATH.read_text().splitlines()
|
| 35 |
out, found = [], False
|
| 36 |
for line in lines:
|
|
|
|
| 41 |
out.append(line)
|
| 42 |
if not found:
|
| 43 |
out.append(f"{var_name}={value}")
|
| 44 |
+
|
| 45 |
ENV_PATH.write_text("\n".join(out) + "\n")
|
| 46 |
+
os.environ[var_name] = value # also set for this process
|
utils/env.py
CHANGED
|
@@ -14,4 +14,4 @@ def temp_env(var: str, value: str | None):
|
|
| 14 |
if old is None:
|
| 15 |
os.environ.pop(var, None)
|
| 16 |
else:
|
| 17 |
-
os.environ[var] = old
|
|
|
|
| 14 |
if old is None:
|
| 15 |
os.environ.pop(var, None)
|
| 16 |
else:
|
| 17 |
+
os.environ[var] = old
|