Spaces:
Sleeping
Sleeping
| """Central configuration: model ids, storage paths, and pipeline constants. | |
| Everything tunable lives here so models/limits can be swapped in one place. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from pathlib import Path | |
| # --- Models (all served via HF Inference Providers, billed to the user's token) --- | |
| # Fast, capable general model used for reasoning-style tasks (search terms, image prompts). | |
| MODEL_REASONING = os.environ.get("MODEL_REASONING", "openai/gpt-oss-120b") | |
| # Strong long-form writer for the actual blog post, with a fallback if unavailable. | |
| MODEL_WRITER = os.environ.get("MODEL_WRITER", "deepseek-ai/DeepSeek-V3-0324") | |
| MODEL_WRITER_FALLBACK = os.environ.get("MODEL_WRITER_FALLBACK", "Qwen/Qwen2.5-72B-Instruct") | |
| # Text-to-image model (as requested). Generated via remote Inference Providers — this | |
| # Space has no GPU, so images are always produced by serverless inference calls. | |
| MODEL_IMAGE = os.environ.get("MODEL_IMAGE", "black-forest-labs/FLUX.1-schnell") | |
| # Providers that currently serve FLUX.1-schnell, tried in order after auto-routing. | |
| # One user-token InferenceClient per provider; billing follows the token. | |
| IMAGE_PROVIDERS = [ | |
| p.strip() for p in os.environ.get( | |
| "IMAGE_PROVIDERS", "fal-ai,nscale,together,hf-inference,replicate,wavespeed" | |
| ).split(",") if p.strip() | |
| ] | |
| # Vision-language model for captioning generated images. | |
| MODEL_VISION = os.environ.get("MODEL_VISION", "Qwen/Qwen2.5-VL-72B-Instruct") | |
| # --- External services --- | |
| SEARXNG_URL = os.environ.get("SEARXNG_URL", "http://127.0.0.1:8080") | |
| OPR_API_KEY = os.environ.get("OPR_API_KEY", "") | |
| OPR_ENDPOINT = "https://openpagerank.com/api/v1.0/getPageRank" | |
| # --- Pipeline constants --- | |
| N_SEARCH_TERMS = int(os.environ.get("N_SEARCH_TERMS", "5")) # queries generated by the LLM | |
| TOP_N = int(os.environ.get("TOP_N", "25")) # results ranked by OpenPageRank | |
| TOP_K = int(os.environ.get("TOP_K", "5")) # top pages used as source material | |
| N_IMAGES = int(os.environ.get("N_IMAGES", "3")) # illustrations per post | |
| DEFAULT_WORD_COUNT = int(os.environ.get("DEFAULT_WORD_COUNT", "1200")) # target post length | |
| SOURCE_CHAR_CAP = int(os.environ.get("SOURCE_CHAR_CAP", "4000")) # chars kept per source page | |
| HTTP_TIMEOUT = int(os.environ.get("HTTP_TIMEOUT", "20")) # seconds for outbound HTTP | |
| def _resolve_data_dir() -> Path: | |
| """Prefer HF persistent storage (/data); fall back to a local dir if not writable.""" | |
| candidate = Path(os.environ.get("DATA_DIR", "/data")) | |
| try: | |
| candidate.mkdir(parents=True, exist_ok=True) | |
| probe = candidate / ".write_test" | |
| probe.write_text("ok", encoding="utf-8") | |
| probe.unlink() | |
| return candidate | |
| except Exception: | |
| fallback = Path(__file__).resolve().parent.parent / ".cache" | |
| fallback.mkdir(parents=True, exist_ok=True) | |
| return fallback | |
| DATA_DIR = _resolve_data_dir() | |
| CACHE_DIR = DATA_DIR / "cache" | |
| OUT_DIR = DATA_DIR / "out" | |
| CACHE_DIR.mkdir(parents=True, exist_ok=True) | |
| OUT_DIR.mkdir(parents=True, exist_ok=True) | |