251 lines
14 KiB
Bash
251 lines
14 KiB
Bash
# ── 数字我 / Digital Me — backend env ─────────────────────────────────
|
||
# Copy to `.env` and fill in. Everything optional degrades gracefully
|
||
# (the product stays usable end-to-end even with no AI keys).
|
||
|
||
PORT=3701
|
||
NODE_ENV=development
|
||
|
||
# 系统版本(独立部署两个系统时各自锁定):
|
||
# adult = 成人系统(社交/广场/群聊/专家付费/钱包)
|
||
# teen = 青少年教育系统(错题/互考/排行榜/家长监护)
|
||
# both = 单体平台(默认)
|
||
# 两系统应各自独立部署:独立 EDITION + 独立 MONGO_DB(或 COLLECTION_PREFIX) + 独立域名。
|
||
EDITION=both
|
||
|
||
# Public origin of THIS api. DashScope pulls media (photo/audio) BY URL,
|
||
# so for avatar 捏脸 / 口播视频 to work this MUST be publicly reachable
|
||
# (a localhost URL fails — those features degrade, chat still works).
|
||
PUBLIC_URL=http://localhost:3701
|
||
|
||
# Web app origin(s), comma-separated.
|
||
CORS_ORIGINS=http://localhost:5173
|
||
|
||
# Auth
|
||
JWT_SECRET=change-me-in-prod
|
||
JWT_EXPIRES=7d
|
||
|
||
# 登录方式:邮箱密码(内置)+ 手机短信 + 微信扫码。
|
||
# 短信:设 SMS_PROVIDER=aliyun 走真实发送(需下列四项全配齐);留空=stub(验证码在
|
||
# 响应 devCode 返回,仅 dev;生产 stub 默认 fail-closed,除非 ALLOW_STUB_LOGIN=true)。
|
||
SMS_PROVIDER=stub
|
||
ALIYUN_SMS_KEY_ID= # 阿里云 AccessKey ID(建议用 RAM 子账号,仅授 AliyunDysmsFullAccess)
|
||
ALIYUN_SMS_KEY_SECRET= # 对应 AccessKey Secret
|
||
ALIYUN_SMS_SIGN= # 短信签名(控制台「国内消息-签名管理」审核通过的签名名称)
|
||
ALIYUN_SMS_TEMPLATE= # 短信模板 CODE(如 SMS_123456789,验证码类模板)
|
||
# 模板正文里的验证码变量名。默认 code(对应模板 ${code});模板用别的变量名时改这里。
|
||
ALIYUN_SMS_CODE_PARAM=code
|
||
# 微信【网站应用】扫码登录(open.weixin.qq.com 开放平台,scope=snsapi_login)。
|
||
# 留空=stub 二维码(本地可模拟扫码;生产 fail-closed 除非 ALLOW_STUB_LOGIN=true)。
|
||
# ⚠ 开放平台后台「网站应用 → 授权回调域」必须填 WECHAT_REDIRECT_URI 的域名(只填域名,不带路径/协议)。
|
||
# ⚠ 拿真实昵称/头像会调 sns/userinfo;unionid 需该应用已绑定到【开放平台账号】才返回(用于统一身份)。
|
||
WECHAT_APP_ID=
|
||
WECHAT_APP_SECRET=
|
||
# 回调地址,须公网可达。留空默认 ${PUBLIC_URL}/api/auth/wechat/callback。
|
||
WECHAT_REDIRECT_URI=
|
||
|
||
# MongoDB — Digital Me owns its own DB. Never share another product's.
|
||
MONGO_URI=mongodb://localhost:27017
|
||
MONGO_DB=digital_me
|
||
|
||
# ── AI: 阿里云 DashScope (one key powers LLM + embeddings + 万相 + EMO + CosyVoice) ──
|
||
DASHSCOPE_API_KEY=
|
||
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||
LLM_MODEL=qwen-max
|
||
EMBED_MODEL=text-embedding-v3
|
||
# 通用图片生成(万相文生图)模型。复用 DASHSCOPE key,有 key 即可用(需百炼已开通万相文生图)。
|
||
# 可选:wanx2.1-t2i-turbo(快省·默认) / wanx2.1-t2i-plus(更精更贵)。经统一入口 POST /api/create(modality=image)。
|
||
WANX_T2I_MODEL=wanx2.1-t2i-turbo
|
||
|
||
# ── 二创·AI 音乐生成:昆仑万维 Mureka ──────────────────────────────────
|
||
# 配 MUREKA_API_KEY 即启用(经 POST /api/create type=music:词+曲风→成品歌)。缺 key → 音乐生成 503。
|
||
# ⚠ 数据出境:歌词/曲风会发往 MUREKA_BASE_URL(默认 api.mureka.ai);合规要境内就指到 Mureka 境内 API 域。
|
||
MUREKA_API_KEY=
|
||
MUREKA_BASE_URL=https://api.mureka.ai
|
||
MUREKA_MODEL=auto # auto / mureka-6 / V8 等
|
||
|
||
# ── 二创·AI 视频生成:字节 Seedance(火山方舟)──────────────────────────
|
||
# 配 SEEDANCE_API_KEY(=火山方舟 API Key)即启用(经 POST /api/create type=drama:文/图生视频)。缺 key → 503。
|
||
# 端点走火山方舟【境内北京】域,数据不出域友好。model 需与你账号已开通的一致;若账号要求推理接入点,
|
||
# 把 SEEDANCE_MODEL 设成 ep-xxxxx。
|
||
SEEDANCE_API_KEY=
|
||
SEEDANCE_BASE_URL=https://ark.cn-beijing.volces.com
|
||
SEEDANCE_MODEL=doubao-seedance-1-0-pro-250528
|
||
# 知识检索精排模型。gte-rerank 已于 2026-05-30 下线,默认用后继 qwen3-rerank。
|
||
RERANK_MODEL=qwen3-rerank
|
||
|
||
# ── 语音合成 CosyVoice ──────────────────────────────────────────────
|
||
# 新克隆音色的注册版本(默认已升 v3.5-flash;高质可用 cosyvoice-v3.5-plus)。
|
||
# ⚠ v3.5 仅北京地域,需在百炼【北京】工作空间开通 CosyVoice;旧 v2 克隆音仍按各自版本合成。
|
||
COSYVOICE_MODEL=cosyvoice-v3.5-flash
|
||
# 预置音色 TTS(助手讲解 / 无克隆音兜底)的模型。预置音色名分版本、v3.5 官方未公布 →
|
||
# 默认仍 v2;待 v3.5 音色公布后,改这里 + 相应 TWIN_COSY_PRESET/ASSISTANT_COSY_VOICE 音色名。
|
||
COSYVOICE_PRESET_MODEL=cosyvoice-v2
|
||
# 实时合成 WebSocket 端点。默认北京全局端点;若工作空间要求专属 MaaS 端点再填。
|
||
# COSYVOICE_WS_URL=wss://<WorkspaceId>.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
|
||
|
||
# 向量索引后端。留空 → memory(MongoDB 内联向量 + 内存暴力余弦,有 2000 块上限,适合小规模)。
|
||
# 配了 DASHVECTOR_ENDPOINT + DASHVECTOR_API_KEY → 自动切阿里云 DashVector(境内托管向量库,ANN 索引,
|
||
# 数据不出域,去掉 2000 块上限)。首次接入或换维度后跑一次:node scripts/reindex-vectors.js
|
||
# DASHVECTOR_DIM 必须与 EMBED_MODEL 维度一致(text-embedding-v3 = 1024)。
|
||
DASHVECTOR_ENDPOINT=
|
||
DASHVECTOR_API_KEY=
|
||
DASHVECTOR_COLLECTION=digitalme_knowledge
|
||
DASHVECTOR_DIM=1024
|
||
|
||
# Optional Claude fallback when Qwen is unavailable.
|
||
ANTHROPIC_API_KEY=
|
||
ANTHROPIC_MODEL=claude-haiku-4-5-20251001
|
||
|
||
# 标准英文发音 (Azure Neural TTS) — 英语陪练用原生发音。留空则英文回退
|
||
# CosyVoice(克隆音色) 或浏览器 TTS。
|
||
AZURE_SPEECH_KEY=
|
||
AZURE_SPEECH_REGION=eastasia
|
||
AZURE_VOICE_EN=en-US-JennyNeural
|
||
|
||
# Avatar 捏脸 (通义万相 wanx-style-repaint). Blank → uploaded photo used flat.
|
||
# 'dashscope' reuses DASHSCOPE_API_KEY. Style: a name (3d/anime/ink/fresh)
|
||
# or raw wanx style_index 0-9. For a realistic "self" twin, leaving the
|
||
# uploaded photo flat (blank provider) is often the most faithful.
|
||
AVATAR_PROVIDER=
|
||
AVATAR_STYLE=3d
|
||
|
||
# Storage: 配齐下面 OSS_* 四要素 → 自动用阿里云 OSS(推荐:公网直链、免公网穿透、
|
||
# 重部署不丢片、DashScope 直接按 URL 拉);否则回落本地磁盘 + /uploads。
|
||
STORAGE_DRIVER=local
|
||
STORAGE_LOCAL_DIR=./data/uploads
|
||
# ── 阿里云 OSS(媒体存储,生产推荐)──────────────────────────────────
|
||
# ⚠ OSS_REGION 必须带 oss- 前缀(如 oss-cn-hangzhou),否则 SDK 拼错域名 ENOTFOUND。
|
||
# 存进 DB 的是持久直链(头像/成片长期展示)→ bucket 需「公开读」,或用 OSS_PUBLIC_BASE
|
||
# 指向自定义域名/CDN。共享 bucket 靠 OSS_PREFIX 隔离(digital-me 用 digitalme)。
|
||
OSS_REGION=
|
||
OSS_BUCKET=
|
||
OSS_ACCESS_KEY_ID=
|
||
OSS_ACCESS_KEY_SECRET=
|
||
OSS_ENDPOINT=
|
||
OSS_PREFIX=digitalme
|
||
OSS_PUBLIC_BASE=
|
||
|
||
# ── 生产级安全 (production hardening) ─────────────────────────────────
|
||
# In production (NODE_ENV=production) the server REFUSES to boot unless
|
||
# JWT_SECRET is set to a strong random value (not the default).
|
||
|
||
# Encrypt visitor chat logs at rest (AES-256-GCM). Any string → hashed to
|
||
# a 32-byte key. Strongly recommended in prod; empty = plaintext (dev only).
|
||
DATA_ENC_KEY=
|
||
|
||
# Emails (comma-separated) allowed to grant 蓝V verification & admin actions.
|
||
SUPER_ADMIN_EMAILS=
|
||
|
||
# Content moderation. Tiers (highest available wins, falls back down):
|
||
# external — set MODERATION_URL (plug a pro service; POST {text} → {allowed,category?})
|
||
# llm — set MODERATION_MODE=llm to classify via DashScope (Qwen)
|
||
# local — built-in regex floor (always on)
|
||
MODERATION_MODE=
|
||
MODERATION_URL=
|
||
MODERATION_KEY=
|
||
|
||
# Max length of any chat/visitor message (cost + abuse control).
|
||
MAX_QUESTION_LEN=2000
|
||
|
||
# Set 'true' when behind nginx/cloudflare so client IP (rate-limit key) is
|
||
# correct. Auto-on in production; set 'false' to force off.
|
||
TRUST_PROXY=
|
||
|
||
# ── 请求访问日志 ──────────────────────────────────────────────────────
|
||
# 每个请求打一行(方法/路径/状态码/耗时/IP/请求ID)。只记元数据,不记 query/body。
|
||
LOG_REQUESTS=on # off 关闭访问日志
|
||
LOG_SLOW_MS=5000 # 超过该耗时(ms)的请求标记 ⚠slow
|
||
LOG_SKIP_PATHS=/health # 不记的高频噪声路径(逗号分隔,前缀匹配)
|
||
|
||
# ── 付费咨询 / 钱包 (FR-4.2) ──────────────────────────────────────────
|
||
# 支付通道:
|
||
# stub = 即时到账(最快开发态)
|
||
# mock = 完整模拟「下单→支付→回调入账」异步链路(不涉及真钱,可本地验证)
|
||
# stripe = Stripe Checkout(需 STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET)
|
||
# wechat = 预留(在 payments.js 实现下单 + 回调)
|
||
PAYMENT_PROVIDER=stub
|
||
TOKENS_PER_YUAN=10
|
||
PAY_CURRENCY=cny
|
||
# 用户支付后返回的前端地址(默认取 CORS_ORIGINS 第一个)。
|
||
WEB_BASE_URL=
|
||
|
||
# 分享卡片 og meta(/me/:slug、/s/:token 的微信/IM 富卡片)。见 DEPLOY.md。
|
||
# 填了→读真 SPA index 注入 meta(页面仍是完整 App);空→回落 meta+跳转独立壳。
|
||
SPA_INDEX_PATH=
|
||
# 可选:无头像时的兜底卡片图(绝对 URL)。
|
||
OG_FALLBACK_IMAGE=
|
||
|
||
# 微信 JS-SDK(公众号「转发给朋友/朋友圈」自定义卡片)。填【公众号】appId/secret
|
||
# (非开放平台扫码登录的那个)。空 → 签名接口 {configured:false}、前端休眠。见 DEPLOY.md。
|
||
# 还需在公众号后台把 digitalme.invoratec.cn 加进「JS 安全域名」。
|
||
WX_MP_APP_ID=
|
||
WX_MP_APP_SECRET=
|
||
# Stripe(provider=stripe 时必填)。Webhook 配到 /api/wallet/webhook/stripe。
|
||
STRIPE_SECRET_KEY=
|
||
STRIPE_WEBHOOK_SECRET=
|
||
|
||
# ── 产品工厂 购买通道 (商店/buy → 购买即开通) ─────────────────────────
|
||
# STORE_PROVIDER:只管【stub ↔ 真实支付】总闸,与「用哪个渠道」正交(渠道见 PAY_METHODS)。
|
||
# stub = 即时开通(无真实收款,开发/演示用,默认)
|
||
# live(或wechat) = 真实支付(非 stub 即视为开)。具体渠道由 PAY_METHODS 决定:
|
||
# · 微信:需 WXPAY_* 配齐(微信内 JSAPI 还需 WX_MP_* + 公众号绑商户号)
|
||
# · 支付宝:需 ALIPAY_* 证书三件套配齐
|
||
STORE_PROVIDER=stub
|
||
# 测试收款:PAY_ENV=dev 或 test 时,所有付费订单只收 1 分钱——走真实通道验证下单→
|
||
# 收银台→回调→开通全链,但只花 1 分。免费 SKU(¥0) 不受影响。生产留空。
|
||
PAY_ENV=
|
||
# 支付弹窗展示哪些收款方式 + 顺序(逗号分隔,只认 wechat/alipay)。留空默认 wechat,alipay。
|
||
# PAY_METHODS=wechat,alipay → 微信在前;=alipay → 只显示支付宝;=wechat → 只微信。
|
||
PAY_METHODS=wechat,alipay
|
||
# 下单显式超时(分钟):过期后二维码/支付链接失效,渠道自动关单。前端轮询时长与之对齐。
|
||
PAY_ORDER_TIMEOUT_MIN=10
|
||
|
||
# 微信支付 v3(商户平台 → API 安全)。Webhook 配到 /api/store/webhook/wechat。
|
||
WXPAY_APP_ID= # 商户绑定的 appid(JSAPI 用 WX_MP_APP_ID 那个公众号;Native 可公众号/开放平台)
|
||
WXPAY_MCH_ID= # 商户号
|
||
WXPAY_API_V3_KEY= # APIv3 密钥(必须 32 位)
|
||
WXPAY_CERT_SERIAL= # 商户 API 证书序列号
|
||
# 商户私钥 PEM:二选一。直接给内容(把换行写成 \n) 或给文件路径。
|
||
WXPAY_PRIVATE_KEY=
|
||
WXPAY_PRIVATE_KEY_PATH=
|
||
# 微信支付【平台证书】(回调验签用公钥)。配上即启用「回调验签闸」(防伪造/重放);
|
||
# 未配时回调仅靠 APIv3 GCM 鉴权放行。二选一:贴内容(\n 转义) 或给文件路径。
|
||
WECHATPAY_PLATFORM_CERT=
|
||
WECHATPAY_PLATFORM_CERT_PATH=
|
||
|
||
# 支付宝 · 电脑网站支付【证书模式/RSA2】。Webhook 配到 /api/store/webhook/alipay。
|
||
# 证书三件套从开放平台下载;每项二选一:贴内容(\n 转义) 或给 *_PATH 文件路径。
|
||
# ALIPAY_APP_CERT = 应用公钥证书 appCertPublicKey_2021xxx.crt
|
||
# ALIPAY_CERT = 支付宝公钥证书 alipayCertPublicKey_RSA2.crt
|
||
# ALIPAY_ROOT_CERT = 支付宝根证书 alipayRootCert.crt
|
||
# 沙箱:ALIPAY_GATEWAY=https://openapi.alipaydev.com/gateway.do(生产留空即用默认生产网关)。
|
||
ALIPAY_APP_ID=
|
||
ALIPAY_PRIVATE_KEY=
|
||
ALIPAY_PRIVATE_KEY_PATH=
|
||
ALIPAY_APP_CERT=
|
||
ALIPAY_APP_CERT_PATH=
|
||
ALIPAY_CERT=
|
||
ALIPAY_CERT_PATH=
|
||
ALIPAY_ROOT_CERT=
|
||
ALIPAY_ROOT_CERT_PATH=
|
||
ALIPAY_GATEWAY=
|
||
|
||
# ── 拟人化互动合规 ────────────────────────────────────────────────────
|
||
# 《人工智能拟人化互动服务管理暂行办法》(网信办/发改委/工信部/公安部/市场监管总局
|
||
# 五部门,2026-04-10 公布,2026-07-15 施行)。本产品的「数字分身」命中第二条
|
||
# 「模拟自然人人格特征、思维模式和沟通风格」要件,故第十四/十八条的义务适用。
|
||
#
|
||
# 未成年人模式(第十四条)总开关。⚠ 默认【开】——它是法定义务不是产品特性,
|
||
# 不配这个变量也是开的。设 off 仅供【误伤大面积用户时先关再修】的紧急止血,
|
||
# 关闭期间本站不符合第十四条,必须同步上报。
|
||
FEATURE_MINOR_MODE=on
|
||
# 未成年人模式下单日累计使用时长上限(分钟)。法条只写「使用时长限制」没给数字,
|
||
# 这里取《未成年人网络保护条例》的通行口径 60 分钟。调整前请过法务。
|
||
MINOR_DAILY_LIMIT_MIN=60
|
||
# 「定期现实提醒」周期(分钟):每隔这么久提醒一次"这是 AI,去看看现实里的人和事"。
|
||
MINOR_REALITY_CHECK_MIN=20
|
||
# 第十四条要求「提供相应申诉渠道」。站内申诉入口已内置(minor_appeals 集合 + 超管处理),
|
||
# 但法条要的是【用户看得见、联系得上】的渠道 → 生产【应当】填一个真实邮箱或电话。
|
||
# 留空时前端只显示站内申诉,并诚实写明"仅站内受理"。
|
||
COMPLIANCE_APPEAL_CONTACT=
|