111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
"""项目配置:路径、模型、网关、发布目标。
|
|
|
|
原则:API key 不落本项目文件,运行时从 Pi 的 auth.json 读取。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
HOME = Path.home()
|
|
|
|
# ---------------------------------------------------------------- 目录
|
|
PROJECT_DIR = Path(__file__).resolve().parents[2] # /home/chendy/df-annals
|
|
DATA_DIR = PROJECT_DIR / "data" # 原始数据,不入库
|
|
EXPORT_DIR = DATA_DIR / "exports" # legends 导出原始文件
|
|
OUTPUT_DIR = PROJECT_DIR / "output" # 成品,入库
|
|
CHAPTER_DIR = OUTPUT_DIR / "chapters"
|
|
PROMPT_DIR = PROJECT_DIR / "prompts"
|
|
|
|
# ---------------------------------------------------------------- 游戏(Windows 侧)
|
|
WINDOWS_USER = "23518"
|
|
WIN_DF_ROOT = Path(f"/mnt/c/Users/{WINDOWS_USER}/DwarfFortress") # 下载/安装根目录
|
|
WIN_DF_DIR_CANDIDATES = [
|
|
WIN_DF_ROOT / "df_53_16_win",
|
|
WIN_DF_ROOT / "Dwarf Fortress",
|
|
WIN_DF_ROOT,
|
|
]
|
|
DF_VERSION = "53.16"
|
|
DFHACK_VERSION = "53.16-r2"
|
|
|
|
# ---------------------------------------------------------------- LLM 网关
|
|
PI_AUTH_JSON = HOME / ".pi/agent/auth.json"
|
|
PI_MODELS_JSON = HOME / ".pi/agent/models.json"
|
|
PROVIDER = "workbuddy"
|
|
MODEL = "cn:deepseek-v4-pro"
|
|
# 该模型是推理模型:思考与正文共用 max_tokens,必须留足
|
|
MAX_TOKENS_CHAPTER = 16000
|
|
MAX_TOKENS_UTIL = 4000
|
|
|
|
# ---------------------------------------------------------------- 发布
|
|
GITEA_SSH_HOST = "124.222.29.26"
|
|
GITEA_SSH_PORT = 2222
|
|
GITEA_USER = "gitadmin"
|
|
GITEA_REPO = "dwarf-fortress-annals"
|
|
GITEA_WEB = "http://124.222.29.26:3000"
|
|
GITEA_REMOTE = f"ssh://git@{GITEA_SSH_HOST}:{GITEA_SSH_PORT}/{GITEA_USER}/{GITEA_REPO}.git"
|
|
SSH_KEY = HOME / ".ssh/id_ed25519"
|
|
|
|
# ---------------------------------------------------------------- 世界与章节
|
|
WORLD_SIZE = "Medium"
|
|
WORLD_HISTORY_YEARS = 250
|
|
CHAPTER_MIN_CHARS = 800
|
|
CHAPTER_MAX_CHARS = 1600 # 契约上限 1500,留出标点/换行余量
|
|
|
|
|
|
@dataclass
|
|
class Gateway:
|
|
base_url: str
|
|
key: str
|
|
model: str = MODEL
|
|
provider: str = PROVIDER
|
|
|
|
|
|
def load_gateway(provider: str | None = None) -> Gateway:
|
|
"""从 Pi 配置读取网关地址与密钥。密钥只驻留内存,不打印、不落盘。"""
|
|
provider = provider or PROVIDER
|
|
|
|
def _read_json(path: Path, label: str) -> dict:
|
|
try:
|
|
return json.loads(path.read_text())
|
|
except FileNotFoundError:
|
|
raise SystemExit(f"找不到 Pi 的{label}文件: {path}") from None
|
|
except json.JSONDecodeError as exc:
|
|
raise SystemExit(f"Pi 的{label}文件不是合法 JSON: {path} ({exc})") from None
|
|
|
|
auth = _read_json(PI_AUTH_JSON, "凭据")
|
|
models = _read_json(PI_MODELS_JSON, "模型配置")
|
|
providers = models.get("providers", models)
|
|
if provider not in providers:
|
|
raise SystemExit(f"Pi 配置里没有 provider: {provider}")
|
|
if provider not in auth:
|
|
raise SystemExit(f"Pi 未授权 provider: {provider}")
|
|
entry = auth[provider]
|
|
key = entry.get("key") if isinstance(entry, dict) else entry
|
|
if not key:
|
|
raise SystemExit(f"provider {provider} 的凭据为空")
|
|
return Gateway(base_url=providers[provider]["baseUrl"].rstrip("/"), key=key, provider=provider)
|
|
|
|
|
|
def find_df_dir() -> Path:
|
|
"""定位已安装的 DF 目录(含 Dwarf Fortress.exe)。"""
|
|
override = os.environ.get("DF_DIR")
|
|
if override:
|
|
p = Path(override)
|
|
if p.is_dir():
|
|
return p
|
|
raise SystemExit(f"DF_DIR 不存在: {p}")
|
|
for cand in WIN_DF_DIR_CANDIDATES:
|
|
if (cand / "Dwarf Fortress.exe").is_file():
|
|
return cand
|
|
raise SystemExit(
|
|
"未找到 Dwarf Fortress.exe。候选路径:" + ", ".join(str(c) for c in WIN_DF_DIR_CANDIDATES)
|
|
)
|
|
|
|
|
|
def ensure_dirs() -> None:
|
|
for d in (DATA_DIR, EXPORT_DIR, OUTPUT_DIR, CHAPTER_DIR, PROMPT_DIR):
|
|
d.mkdir(parents=True, exist_ok=True)
|