# slide-rule-python - requirements for runnable V5 backend
# Modeled on tws-ai-ask-python structure (FastAPI + services for RAG/LLM/knowledge)
# This makes the Python side actually importable and the /api/sliderule surface testable

fastapi>=0.115.0
uvicorn[standard]>=0.30.0
pydantic>=2.9.0
# 配色合规校验（services/palette_guard.py）：OKLCh 转换与色差。手搓 OKLab
# 矩阵能省这个依赖，但色彩空间转换是那种"差一点点就全错、还很难发现"的活，
# 用成熟库更稳。
coloraide>=4.0
# FreeformInsight 内容树是深层嵌套 JSON，LLM 一次性整段吐出来偶发数错括号
# 层数（真机复现过：{}/[] 各差 1、尾巴多一个孤立句号，且不是 token 截断——
# 那份输出结尾收得完整）。这类"语法错但结构基本对"的输出，成熟的修复库
# 比重新问一轮 LLM 更快更稳，用它而不是自己写括号计数式的线性修补——
# 手搓的线性修补容易把内容拼出语法合法但结构错位的树。
json-repair>=0.61
pydantic-settings>=2.5.0
python-dotenv>=1.0.0
httpx>=0.27.0
pytest>=8.0.0

# 目录窄化（services/block_narrowing.py）：按题意从 358 个区块里挑一小批注进
# prompt。BM25 打分用它，numpy-only、无重依赖。
#
# ⚠️ 这条**必须装上**，虽然代码是 fail-open 的。缺了它窄化整个退回全量目录，
# 而窄化不是可有可无的增强——目录里可达的只有前 ~50 个格子，剩下的靠它才够得着
# （对题件被选中 0.67 → 3.25，p=0.00004，见 docs/block-narrowing-eval.md）。
# 2026-08-11 实测踩到：它当时漏在这份清单外，而 Dockerfile 只装这一个文件，
# 部署上去窄化会一声不吭地整个失效。现在缺失会打一行 stderr 告警，
# 并由 tests/test_narrowing_dependency_declared.py 钉住声明。
rank-bm25>=0.2.2

# RAG / retrieval (real external evidence, replacing Node stubs)
qdrant-client>=1.12.0
openai>=1.50.0  # for LLM calls in stable style (reference project uses similar)

# Persistence (sessions, like reference)
sqlalchemy>=2.0.0
pymysql>=1.1.0
# App Store（生成应用持久化 → 组建库地基）：配了 APP_STORE_DATABASE_URL 指向
# Postgres（Neon/自建）时用 psycopg v3 连（支持 Neon 的 channel_binding）；不配
# 走本地 JSON 文件兜底，这条依赖也不会被 import。
psycopg[binary]>=3.2

# P2b execution tools: code.run runs ONLY inside E2B sandbox (fail-closed without key)
e2b-code-interpreter>=2.8.0

# 缩略图编码（2026-08-02）：卡片缩略图从 PNG 换 WebP，实测 805KB → 43KB
# （分辨率不减）。见 services/thumb_image.py。
# 惰性导入 + fail-open：装不上时整条压缩链路静默失效、原样存 PNG，不影响功能。
pillow>=10.4

# 身份体系（2026-08-02）：邮箱注册/登录 + 匿名可读/登录可写/超管三档。
# 密码哈希用 Argon2（内存硬、抗 GPU 爆破），算法选择与写法对齐
# fastapi/full-stack-fastapi-template 与 fastapi-users——两者 2026 年都已
# 把默认从 bcrypt 换成 Argon2。
# ⚠️ 这两条**不 fail-open**：装不上时身份体系整体不可用，而不是降级放行。
#    密码哈希没有"弱一点也能用"的选项。
pwdlib[argon2]>=0.2
pyjwt>=2.8
