soumya-ai/Knowledge-Graph
0
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 