CoolFace
Apppublic

soumya-ai/Knowledge-Graph

sourceHugging Facemitupdated 4mo agoView on Hugging Face
0likes
config.py174 linesDownload Raw Back to src
1"""2config.py — centralised settings loaded from .env or Hugging Face Space secrets.3 4Stack: Neo4j Aura + OpenAI + LangChain5"""6 7import os8from dotenv import load_dotenv9 10# HF injects secrets as env vars before startup; never override them with .env11load_dotenv(override=False)12 13_INGEST_SPACE = "soumya-ai/Knowledge-Graph-Ingest"14_QUERY_SPACE = "soumya-ai/Knowledge-Graph"15HF_SECRETS_URL = (16    f"https://huggingface.co/spaces/{_INGEST_SPACE}/settings"17    if os.getenv("SPACE_ID") == _INGEST_SPACE18    else f"https://huggingface.co/spaces/{_QUERY_SPACE}/settings"19)20 21 22def _is_hf_space() -> bool:23    """Hugging Face Spaces set SPACE_ID at runtime."""24    return bool(os.getenv("SPACE_ID"))25 26 27def _env(key: str, default: str = "") -> str:28    """Read env var, strip whitespace and optional surrounding quotes."""29    val = (os.getenv(key) or default).strip()30    if len(val) >= 2 and val[0] == val[-1] and val[0] in "\"'":31        val = val[1:-1].strip()32    return val33 34 35def _neo4j_uri_from_env() -> str:36    return _env("NEO4J_URI") or _env("NEO4J_URL")37 38 39class Settings:40    """Mutable settings — env on load, or UI overrides on Hugging Face."""41 42    def reload_from_env(self) -> None:43        on_hf = _is_hf_space()44        self.NEO4J_URI = _neo4j_uri_from_env() or (45            "" if on_hf else "bolt://localhost:7687"46        )47        self.NEO4J_USERNAME = _env("NEO4J_USERNAME") or ("" if on_hf else "neo4j")48        self.NEO4J_PASSWORD = _env("NEO4J_PASSWORD") or (49            "" if on_hf else "graphrag123"50        )51        self.NEO4J_DATABASE = _env("NEO4J_DATABASE") or "neo4j"52        self.OPENAI_API_KEY = _env("OPENAI_API_KEY")53        self.OPENAI_MODEL = _env("OPENAI_MODEL", "gpt-4o-mini")54        self.OPENAI_EXTRACT_MODEL = _env("OPENAI_EXTRACT_MODEL", "gpt-4o-mini")55        self.OPENAI_EMBED_MODEL = _env("OPENAI_EMBED_MODEL", "text-embedding-3-small")56        self.OPENAI_EMBED_DIMENSIONS = int(_env("OPENAI_EMBED_DIMENSIONS", "1536"))57 58    def __init__(self) -> None:59        self.reload_from_env()60 61    @property62    def on_huggingface(self) -> bool:63        return _is_hf_space()64 65    def neo4j_missing_keys(self) -> list[str]:66        missing = []67        if not self.NEO4J_URI:68            missing.append("NEO4J_URI")69        if not self.NEO4J_USERNAME:70            missing.append("NEO4J_USERNAME")71        if not self.NEO4J_PASSWORD:72            missing.append("NEO4J_PASSWORD")73        if not self.NEO4J_DATABASE:74            missing.append("NEO4J_DATABASE")75        return missing76 77    def using_local_neo4j_default(self) -> bool:78        if self.on_huggingface:79            return (not self.NEO4J_URI) or ("localhost" in self.NEO4J_URI)80        return self.NEO4J_URI in (81            "bolt://localhost:7687",82            "neo4j://localhost:7687",83        ) and self.NEO4J_PASSWORD == "graphrag123"84 85    def neo4j_ready(self) -> bool:86        return not self.neo4j_missing_keys() and not self.using_local_neo4j_default()87 88 89settings = Settings()90 91 92def apply_runtime_config(93    *,94    neo4j_uri: str = "",95    neo4j_username: str = "",96    neo4j_password: str = "",97    neo4j_database: str = "neo4j",98    openai_api_key: str = "",99) -> None:100    """101    Set credentials from the Gradio UI (session-only).102    Use when Hugging Face Secrets are not configured.103    """104    if neo4j_uri.strip():105        settings.NEO4J_URI = neo4j_uri.strip()106        os.environ["NEO4J_URI"] = settings.NEO4J_URI107    if neo4j_username.strip():108        settings.NEO4J_USERNAME = neo4j_username.strip()109        os.environ["NEO4J_USERNAME"] = settings.NEO4J_USERNAME110    if neo4j_password.strip():111        settings.NEO4J_PASSWORD = neo4j_password.strip()112        os.environ["NEO4J_PASSWORD"] = settings.NEO4J_PASSWORD113    if neo4j_database.strip():114        settings.NEO4J_DATABASE = neo4j_database.strip()115        os.environ["NEO4J_DATABASE"] = settings.NEO4J_DATABASE116    if openai_api_key.strip():117        settings.OPENAI_API_KEY = openai_api_key.strip()118        os.environ["OPENAI_API_KEY"] = settings.OPENAI_API_KEY119 120    from src.neo4j_client import reset_graph121 122    reset_graph()123 124 125def require_openai_key() -> None:126    if not settings.OPENAI_API_KEY:127        raise ValueError(128            "OPENAI_API_KEY is not set. Add it under Space Secrets, use the "129            f"connection form below, or set it in .env locally: {HF_SECRETS_URL}"130        )131 132 133def require_neo4j_config() -> None:134    missing = settings.neo4j_missing_keys()135    if missing:136        raise ValueError(137            f"Neo4j not configured. Missing: {', '.join(missing)}. "138            "Fill in **Connect to Neo4j Aura** below, or add Space secrets at "139            f"{HF_SECRETS_URL} and **Restart**."140        )141    if settings.using_local_neo4j_default():142        raise ValueError(143            "Neo4j Aura is not configured. Use the connection form below or add "144            f"secrets at {HF_SECRETS_URL} then **Restart**."145        )146 147 148def get_config_status() -> str:149    """Human-readable config check for Gradio / HF Space startup."""150    lines: list[str] = []151 152    if settings.on_huggingface:153        lines.append(154            "Running on **Hugging Face Spaces**. Set [Secrets](%s) **or** use "155            "**Connect to Neo4j Aura** below (session only)." % HF_SECRETS_URL156        )157 158    if not settings.OPENAI_API_KEY:159        lines.append("⚠️ Missing `OPENAI_API_KEY`.")160    else:161        lines.append(f"✅ OpenAI configured (`{settings.OPENAI_MODEL}`).")162 163    if not settings.neo4j_ready():164        lines.append(165            "⚠️ Neo4j not connected — enter credentials in the form below."166        )167    else:168        from src.neo4j_client import test_neo4j_connection169 170        ok, msg = test_neo4j_connection()171        lines.append(f"{'✅' if ok else '❌'} {msg}")172 173    return "\n\n".join(lines)174