File size: 3,256 Bytes
981d8b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Deploy this app to Hugging Face Spaces (Docker SDK) and print the live URL.

Requires:
  * `pip install -r requirements-deploy.txt` (huggingface_hub — deploy-only dep)
  * a Hugging Face token (cached via `huggingface-cli login`, or HF_TOKEN env)
  * OPENROUTER_API_KEY (read from env or .streamlit/secrets.toml) — set as a
    Space secret so the deployed app can call OpenRouter.

    python scripts/deploy_hf.py [--space-name text-to-sql-guardrails]
"""

from __future__ import annotations

import argparse
import os
import sys
import tempfile
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]

SPACE_README = """---
title: Text-to-SQL with Guardrails
emoji: 🛡️
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
short_description: NL to SQL with read-only guardrails + execution eval
---

# Text-to-SQL with Guardrails

Ask a question in plain English; an LLM writes SQL, a guardrail layer validates it
(read-only, single-statement, table-allowlist, no file functions) using `sqlglot`,
and only then does it run on a real DuckDB. Includes an execution-accuracy eval.

Source: https://github.com/saiteja007-mv/text-to-sql-guardrails
"""

IGNORE = [
    ".venv/*",
    ".git/*",
    ".github/*",
    "__pycache__/*",
    "*/__pycache__/*",
    "*.pyc",
    ".streamlit/secrets.toml",
    ".streamlit/secrets.toml.example",
    ".env",
    "tests/*",
    "docs/*",
    ".boot.log",
    "README.md",  # replaced by the Space README with YAML front-matter
]


def _load_key() -> str | None:
    key = os.environ.get("OPENROUTER_API_KEY")
    if key:
        return key.strip()
    sec = ROOT / ".streamlit" / "secrets.toml"
    if sec.exists():
        import tomllib

        return str(tomllib.load(sec.open("rb")).get("OPENROUTER_API_KEY", "")).strip() or None
    return None


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--space-name", default="text-to-sql-guardrails")
    args = ap.parse_args()

    from huggingface_hub import HfApi

    api = HfApi()
    user = api.whoami()["name"]
    repo_id = f"{user}/{args.space_name}"
    print(f"[deploy] HF user: {user} -> space {repo_id}")

    api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="docker", exist_ok=True)

    key = _load_key()
    if key:
        api.add_space_secret(repo_id=repo_id, key="OPENROUTER_API_KEY", value=key)
        print("[deploy] set Space secret OPENROUTER_API_KEY")
    else:
        print("[deploy] WARNING: no OPENROUTER_API_KEY found — set it in Space settings.")

    with tempfile.TemporaryDirectory() as td:
        readme = Path(td) / "README.md"
        readme.write_text(SPACE_README, encoding="utf-8")
        api.upload_file(
            path_or_fileobj=str(readme),
            path_in_repo="README.md",
            repo_id=repo_id,
            repo_type="space",
        )

    api.upload_folder(
        folder_path=str(ROOT),
        repo_id=repo_id,
        repo_type="space",
        ignore_patterns=IGNORE,
        commit_message="Deploy text-to-sql-guardrails",
    )

    url = f"https://huggingface.co/spaces/{repo_id}"
    print(f"\n[deploy] DONE. Live (build takes ~1-2 min):\n  {url}")
    return 0


if __name__ == "__main__":
    sys.exit(main())