2026-02-23 20:12:10 -06:00

148 lines
5.6 KiB
Python

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()
CLOUDAI_TIMEOUT = int(os.getenv("JOURNAL_CLOUDAI_TIMEOUT", "30").strip() or "30")
if CLOUDAI_TIMEOUT <= 0:
CLOUDAI_TIMEOUT = 30
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()