import sys import os from pathlib import Path sys.path.append(str(Path(__file__).resolve().parent.parent)) # --- Directories --- PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent # Optional local dependency target used by scripts/pip-min.ps1 on constrained hosts. LOCAL_PYDEPS_DIR = PROJECT_ROOT / ".pydeps" / f"py{sys.version_info.major}{sys.version_info.minor}" if LOCAL_PYDEPS_DIR.exists(): local_pydeps = str(LOCAL_PYDEPS_DIR) if local_pydeps not in sys.path: sys.path.insert(0, local_pydeps) # --- Local model/cache directories --- HF_HOME = os.getenv("JOURNAL_HF_HOME", str(PROJECT_ROOT / ".cache" / "huggingface")).strip() HF_HUB_CACHE = os.getenv("JOURNAL_HF_HUB_CACHE", str(Path(HF_HOME) / "hub")).strip() HF_HUB_DISABLE_SYMLINKS_WARNING = ( os.getenv("HF_HUB_DISABLE_SYMLINKS_WARNING", "1").strip() or "1" ) os.environ.setdefault("HF_HOME", HF_HOME) os.environ.setdefault("HUGGINGFACE_HUB_CACHE", HF_HUB_CACHE) os.environ.setdefault("HF_HUB_DISABLE_SYMLINKS_WARNING", HF_HUB_DISABLE_SYMLINKS_WARNING) DATA_DIR = ( PROJECT_ROOT / "journal" / "data" ) # This will become the temporary decrypted data directory VAULT_DIR = ( PROJECT_ROOT / "journal" / "vault" ) # This will store the encrypted monthly vault files LOG_DIR = PROJECT_ROOT / "logs" PID_FILE = LOG_DIR / "nicegui_server.pid" SERVER_CONTROL_FILE = LOG_DIR / "server_control.action" DATABASE_FILENAME = "journal_cache.db" # --- Vault & Encryption --- SALT_SIZE = 16 KEY_SIZE = 32 # AES-256 AES_NONCE_SIZE = 12 AES_TAG_SIZE = 16 ITERATIONS = 600_000 MONTHLY_VAULT_FORMAT = "%Y-%m.vault" # e.g., 2025-07.vault # --- AI Configuration --- CLOUDAI_API_KEY = os.getenv("JOURNAL_CLOUDAI_API_KEY", "").strip() CLOUDAI_API_URL = os.getenv("JOURNAL_CLOUDAI_API_URL", "").strip() # Read timeout (seconds). Keep high by default for slow local inference. CLOUDAI_TIMEOUT = int(os.getenv("JOURNAL_CLOUDAI_TIMEOUT", "7200").strip() or "7200") if CLOUDAI_TIMEOUT <= 0: CLOUDAI_TIMEOUT = 7200 # Connection timeout (seconds) should stay short; only inference read can be long. CLOUDAI_CONNECT_TIMEOUT = int( os.getenv("JOURNAL_CLOUDAI_CONNECT_TIMEOUT", "10").strip() or "10" ) if CLOUDAI_CONNECT_TIMEOUT <= 0: CLOUDAI_CONNECT_TIMEOUT = 10 LLAMA_CPP_URL = ( os.getenv("JOURNAL_LLAMA_CPP_URL", "http://127.0.0.1:8085/v1/completions").strip() or "http://127.0.0.1:8085/v1/completions" ) LLAMA_CPP_MODEL = os.getenv("JOURNAL_LLAMA_CPP_MODEL", "qwen/qwen3-4b").strip() or "qwen/qwen3-4b" LLAMA_CPP_TIMEOUT = int(os.getenv("JOURNAL_LLAMA_CPP_TIMEOUT", "6000").strip() or "6000") if LLAMA_CPP_TIMEOUT <= 0: LLAMA_CPP_TIMEOUT = 6000 EMBEDDING_API_URL = ( os.getenv("JOURNAL_EMBEDDING_API_URL", "http://127.0.0.1:8086/v1/embeddings").strip() or "http://127.0.0.1:8086/v1/embeddings" ) EMBEDDING_MODEL_NAME = ( os.getenv("JOURNAL_EMBEDDING_MODEL_NAME", "text-embedding-nomic-embed-text-v2-moe").strip() or "text-embedding-nomic-embed-text-v2-moe" ) MODEL_CONTEXT_TOKENS = int(os.getenv("JOURNAL_MODEL_CONTEXT_TOKENS", "131072").strip() or "131072") if MODEL_CONTEXT_TOKENS <= 0: MODEL_CONTEXT_TOKENS = 131072 CHUNK_TOKEN_BUDGET = int(os.getenv("JOURNAL_CHUNK_TOKEN_BUDGET", "120000").strip() or "120000") if CHUNK_TOKEN_BUDGET <= 0: CHUNK_TOKEN_BUDGET = 120000 # --- Hardware Configuration --- # Set this to a specific index from `journal devices list` to force a microphone. # Setting this to `None` is recommended as it will use the system's default device. MICROPHONE_DEVICE_INDEX: int | None = None # --- Speech Recognition --- # "faster-whisper" and "whisper" are local/private options. # "google" is online and sends audio to Google. # "sphinx" is offline and fast but less accurate. _VALID_SPEECH_ENGINES = {"faster-whisper", "whisper", "google", "sphinx"} _VALID_WHISPER_MODELS = {"tiny", "base", "small", "medium", "large"} _VALID_FASTER_WHISPER_DEVICES = {"auto", "cpu", "cuda"} _VALID_FASTER_WHISPER_COMPUTE_TYPES = { "auto", "default", "int8", "int8_float32", "int8_float16", "float16", "float32", } SPEECH_RECOGNITION_ENGINE: str = ( os.getenv("JOURNAL_SPEECH_ENGINE", "faster-whisper").strip().lower() or "faster-whisper" ) if SPEECH_RECOGNITION_ENGINE not in _VALID_SPEECH_ENGINES: SPEECH_RECOGNITION_ENGINE = "faster-whisper" WHISPER_MODEL_SIZE: str = ( os.getenv("JOURNAL_WHISPER_MODEL", "base").strip().lower() or "base" ) if WHISPER_MODEL_SIZE not in _VALID_WHISPER_MODELS: WHISPER_MODEL_SIZE = "base" FASTER_WHISPER_DEVICE: str = ( os.getenv("JOURNAL_FASTER_WHISPER_DEVICE", "auto").strip().lower() or "auto" ) if FASTER_WHISPER_DEVICE not in _VALID_FASTER_WHISPER_DEVICES: FASTER_WHISPER_DEVICE = "auto" FASTER_WHISPER_COMPUTE_TYPE: str = ( os.getenv("JOURNAL_FASTER_WHISPER_COMPUTE_TYPE", "float32").strip().lower() or "float32" ) if FASTER_WHISPER_COMPUTE_TYPE not in _VALID_FASTER_WHISPER_COMPUTE_TYPES: FASTER_WHISPER_COMPUTE_TYPE = "float32" # NLP backend selection: # - auto: use spaCy when available, otherwise fallback heuristics. # - spacy: require spaCy backend and fail clearly if unavailable. # - fallback: always use lightweight fallback heuristics. NLP_BACKEND: str = os.getenv("JOURNAL_NLP_BACKEND", "auto").strip().lower() or "auto" if NLP_BACKEND not in {"auto", "spacy", "fallback"}: NLP_BACKEND = "auto" # --- Ensure directories exist --- DATA_DIR.mkdir(exist_ok=True) VAULT_DIR.mkdir(exist_ok=True) LOG_DIR.mkdir(exist_ok=True) Path(HF_HUB_CACHE).mkdir(parents=True, exist_ok=True) # --- Backend selection --- # python: pure Python backend (C# is Default) # csharp-hybrid: Python UI + C# sidecar for vault, entry, and search operations BACKEND_MODE: str = os.getenv("JOURNAL_BACKEND_MODE", "csharp-hybrid").strip().lower() or "csharp-hybrid" if BACKEND_MODE not in {"python", "csharp-hybrid"}: BACKEND_MODE = "csharp-hybrid" # Optional absolute/relative override for the C# sidecar executable path. CSHARP_SIDECAR_PATH: str = os.getenv("JOURNAL_CSHARP_SIDECAR_PATH", "").strip()