From 2e6f997f0407c5fea711fb7594b7ea5523cc1293 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 11 Mar 2026 16:29:31 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=96=B0=E5=A2=9E=E4=B8=8A=E7=BA=BF?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E5=8D=95=E4=B8=8E=E8=84=B1=E6=95=8F=20env=20?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/.env.example | 128 ++++++++++++++++ api/.env.production | 32 +++- .../liblib-api-python-guide.md | 0 .../tencent-cos-python-sdk-guide.md | 0 ...production-readiness-summary-2026-03-11.md | 137 ++++++++++++++++++ 5 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 api/.env.example rename docs/{ => 3rd-party-api-best-practice}/liblib-api-python-guide.md (100%) rename docs/{ => 3rd-party-api-best-practice}/tencent-cos-python-sdk-guide.md (100%) create mode 100644 docs/before-prod/production-readiness-summary-2026-03-11.md diff --git a/api/.env.example b/api/.env.example new file mode 100644 index 0000000..e473cf5 --- /dev/null +++ b/api/.env.example @@ -0,0 +1,128 @@ +# ============================================================================= +# Life Echo API environment example +# 复制为 .env 或 .env.production 后按实际环境修改 +# 不要把真实密钥提交到仓库 +# ============================================================================= + +# ============================================================================= +# LLM / DeepSeek +# ============================================================================= +DEEPSEEK_API_KEY=your_deepseek_api_key +DEEPSEEK_BASE_URL=https://api.deepseek.com +DEEPSEEK_MODEL=deepseek-chat + +# ============================================================================= +# Database +# ============================================================================= +# 本地开发示例: +# DATABASE_URL=postgresql://postgres:postgres@localhost:5432/life_echo +# Docker / production 示例: +# DATABASE_URL=postgresql://postgres:postgres@postgres:5432/life_echo +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/life_echo + +# ============================================================================= +# Redis +# ============================================================================= +# 本地开发示例: +# REDIS_URL=redis://localhost:6379/0 +# Docker / production 示例: +# REDIS_URL=redis://redis:6379/0 +REDIS_URL=redis://localhost:6379/0 +REDIS_SESSION_TTL=86400 + +# ============================================================================= +# Auth +# ============================================================================= +# 建议使用: openssl rand -hex 32 +SECRET_KEY=replace_with_a_strong_random_secret +ALGORITHM=HS256 +ACCESS_TOKEN_EXPIRE_MINUTES=120 + +# ============================================================================= +# Tencent SMS +# ============================================================================= +TENCENT_SMS_SECRET_ID=your_tencent_sms_secret_id +TENCENT_SMS_SECRET_KEY=your_tencent_sms_secret_key +TENCENT_SMS_SDK_APP_ID=your_sms_sdk_app_id +TENCENT_SMS_SIGN_NAME=your_sms_sign_name +TENCENT_SMS_TEMPLATE_ID=your_sms_template_id +TENCENT_SMS_TEMPLATE_PARAM_COUNT=1 + +# ============================================================================= +# ASR Provider +# whisper | tencent +# ============================================================================= +ASR_PROVIDER=whisper + +# Whisper ASR +ASR_MODEL_SIZE=small +ASR_DEVICE=cpu +ASR_COMPUTE_TYPE=int8 + +# Tencent ASR +# 仅在 ASR_PROVIDER=tencent 时需要 +TENCENT_SECRET_ID=your_tencent_asr_secret_id +TENCENT_SECRET_KEY=your_tencent_asr_secret_key +# TENCENT_ASR_APP_ID= + +# ============================================================================= +# WeChat Pay +# ============================================================================= +WECHAT_PAY_APP_ID=your_wechat_pay_app_id +WECHAT_PAY_MCH_ID=your_wechat_mch_id +WECHAT_PAY_API_V3_KEY=your_wechat_api_v3_key +WECHAT_PAY_PRIVATE_KEY_PATH=certs/apiclient_key.pem +WECHAT_PAY_CERT_SERIAL_NO=your_wechat_cert_serial_no +WECHAT_PAY_NOTIFY_URL=https://your-domain.com/api/payment/notify/wechat +# 可选平台公钥模式 +# WECHAT_PAY_PLATFORM_PUBLIC_KEY_PATH=certs/wechat_platform_public_key.pem +# WECHAT_PAY_PLATFORM_PUBLIC_KEY_ID=your_wechat_platform_public_key_id + +# ============================================================================= +# Alipay +# ============================================================================= +ALIPAY_APP_ID=your_alipay_app_id +ALIPAY_PRIVATE_KEY=your_alipay_private_key +ALIPAY_PUBLIC_KEY=your_alipay_public_key +ALIPAY_NOTIFY_URL=https://your-domain.com/api/payment/notify/alipay + +# ============================================================================= +# Misc +# ============================================================================= +ENABLE_TEST_SUBSCRIPTION=0 + +# ============================================================================= +# Memoir image generation +# ============================================================================= +MEMOIR_IMAGE_ENABLED=false +MEMOIR_IMAGE_MAX_PER_CHAPTER=2 +MEMOIR_IMAGE_POLL_INTERVAL=3 +MEMOIR_IMAGE_MAX_ATTEMPTS=20 +# 正文越长,可允许更多图片 +MEMOIR_IMAGE_CHARS_PER_EXTRA=1500 +MEMOIR_IMAGE_MAX_CAP=8 +MEMOIR_IMAGE_PROVIDER=liblib +MEMOIR_IMAGE_STYLE_DEFAULT=watercolor +MEMOIR_IMAGE_SIZE_DEFAULT=1280x720 +# 可选,限制 Liblib 下载域名 +# MEMOIR_IMAGE_DOWNLOAD_HOSTS=liblib.cloud,liblibai.cloud + +# ============================================================================= +# Liblib image provider +# ============================================================================= +LIBLIB_ACCESS_KEY=your_liblib_access_key +LIBLIB_SECRET_KEY=your_liblib_secret_key +LIBLIB_BASE_URL=https://openapi.liblibai.cloud +LIBLIB_TEMPLATE_UUID=your_liblib_template_uuid + +# ============================================================================= +# Tencent COS for memoir images +# 生产环境请确认这里使用的是生产 bucket,而不是开发 bucket +# ============================================================================= +TENCENT_COS_SECRET_ID=your_tencent_cos_secret_id +TENCENT_COS_SECRET_KEY=your_tencent_cos_secret_key +TENCENT_COS_REGION=ap-shanghai +TENCENT_COS_BUCKET=your_production_bucket +TENCENT_COS_BASE_URL=https://your_production_bucket.cos.ap-shanghai.myqcloud.com +# 可选临时凭证 +# TENCENT_COS_TOKEN= diff --git a/api/.env.production b/api/.env.production index b76a0ec..4d93636 100644 --- a/api/.env.production +++ b/api/.env.production @@ -96,4 +96,34 @@ ALIPAY_PRIVATE_KEY=... ALIPAY_PUBLIC_KEY=... ALIPAY_NOTIFY_URL=https://lifecho.worldsplats.com/api/payment/notify/alipay -ENABLE_TEST_SUBSCRIPTION=1 \ No newline at end of file +ENABLE_TEST_SUBSCRIPTION=1 + +# ============================================================================= +# 回忆录图片生成配置 +# ============================================================================= +# 总开关(true 启用,不设置则关闭) +MEMOIR_IMAGE_ENABLED=false +# 每章最多生成图片数 +MEMOIR_IMAGE_MAX_PER_CHAPTER=2 +# 轮询间隔(秒)和最大尝试次数 +MEMOIR_IMAGE_POLL_INTERVAL=3 +MEMOIR_IMAGE_MAX_ATTEMPTS=20 + +# ============================================================================= +# Liblib 图片生成 API(HMAC-SHA1 签名认证) +# ============================================================================= +LIBLIB_ACCESS_KEY=zrDp6quCOKlLwcewOEfrog +LIBLIB_SECRET_KEY=iTVHo5Nf3KA-xpC1Mja80bC93u6chJem +LIBLIB_BASE_URL=https://openapi.liblibai.cloud +# 星流 Star-3 Alpha 文生图模板(默认值,可按需切换为其他模型) +LIBLIB_TEMPLATE_UUID=5d7e67009b344550bc1aa6ccbfa1d7f4 + +# ============================================================================= +# 腾讯云 COS(回忆录图片存储) +# ============================================================================= +TENCENT_COS_SECRET_ID=AKIDa2ILCwUr56uVt31oU0JOHxPfGhvvkLiq +TENCENT_COS_SECRET_KEY=xiFbjlZ9XheS2NWYLvHRPAh2A5nGYcR2 +TENCENT_COS_REGION=ap-shanghai +# 要把bucket改成生产环境的bucket +TENCENT_COS_BUCKET=life-echo-dev-1319381411 +TENCENT_COS_BASE_URL=https://life-echo-dev-1319381411.cos.ap-shanghai.myqcloud.com \ No newline at end of file diff --git a/docs/liblib-api-python-guide.md b/docs/3rd-party-api-best-practice/liblib-api-python-guide.md similarity index 100% rename from docs/liblib-api-python-guide.md rename to docs/3rd-party-api-best-practice/liblib-api-python-guide.md diff --git a/docs/tencent-cos-python-sdk-guide.md b/docs/3rd-party-api-best-practice/tencent-cos-python-sdk-guide.md similarity index 100% rename from docs/tencent-cos-python-sdk-guide.md rename to docs/3rd-party-api-best-practice/tencent-cos-python-sdk-guide.md diff --git a/docs/before-prod/production-readiness-summary-2026-03-11.md b/docs/before-prod/production-readiness-summary-2026-03-11.md new file mode 100644 index 0000000..5244ea4 --- /dev/null +++ b/docs/before-prod/production-readiness-summary-2026-03-11.md @@ -0,0 +1,137 @@ +# Production 上线判断总结(2026-03-11) + +## 结论 + +当前代码已经接近可上线状态,但是否可以直接进入 `production`,取决于图片功能的上线策略。 + +- 如果接受丢弃历史旧图,并且上线时将 `MEMOIR_IMAGE_ENABLED=false`,则本次改动不需要额外做数据库迁移,整体风险可控,可以作为保守方案进入生产。 +- 如果准备在生产立即启用章节配图功能,则仍需确认生产 COS 资源、Liblib 凭证、Celery worker 部署和新依赖安装均已就绪,之后再启用更稳妥。 + +## 本次评估范围 + +本次评估针对 `8b4a058..HEAD` 期间的改动,重点检查了以下内容: + +- 数据库模型和迁移脚本是否变化 +- API / WebSocket / Celery 是否有生产兼容性风险 +- 回忆录图片链路是否会影响现网章节读取、阅读页和 PDF 导出 +- 生产环境变量和容器部署形态是否能承接新能力 + +## 数据库与迁移判断 + +### 不需要新增 schema 迁移 + +本次区间内没有新增数据库表、字段或字段类型修改。 + +- `api/database/models.py` 中 `Chapter.images` 只有注释语义变化,从“图片 URL 列表”变成“图片元数据对象列表” +- `api/migrations/sync_schema_to_models.sql` 在这段提交区间没有新增迁移内容 + +因此: + +- 不需要新增 SQL migration +- 不需要执行结构性数据迁移 + +## 图片功能判断 + +### `MEMOIR_IMAGE_ENABLED` 不是“全功能总开关” + +这个开关能控制的是: + +- 是否初始化待生成图片资产 +- 是否派发 `generate_chapter_images` 任务 +- 是否在读取章节时过滤掉未完成图片状态 + +这个开关不能完全关闭的内容: + +- 章节正文里的图片占位符注入逻辑仍会存在 +- 已完成图片仍可能继续被返回和渲染 +- 章节接口仍会进入图片归一化逻辑 +- PDF 导出仍会处理已完成图片 + +### 旧 `chapters.images` 数据兼容性 + +历史文档里 `images` 被定义为“图片 URL 列表”,但当前代码要求每个元素都具备至少以下字段: + +- `placeholder` +- `description` + +否则在归一化时会被过滤掉。 + +结论: + +- 如果必须保留历史旧图,需要额外做读兼容或数据修复 +- 如果业务允许丢弃历史旧图,则这项不再构成上线阻塞 + +### 当前推荐策略 + +结合当前讨论结果,推荐采用以下上线策略: + +1. 允许丢弃历史旧图 +2. 生产环境先保持 `MEMOIR_IMAGE_ENABLED=false` +3. 先完成主链路上线 +4. 等生产 COS / Liblib / worker 验证完成后,再单独开启图片能力 + +这样做的好处: + +- 不需要补兼容代码 +- 不需要回填旧数据 +- 能把风险集中在“新生成图片”而不是“历史数据” + +## 生产环境配置判断 + +### 已具备的条件 + +- `Dockerfile` 会安装新的 Python 依赖,包括 `cos-python-sdk-v5` +- `docker-compose.yml` 已包含 `api` 和 `celery-worker` +- `api/.env.production` 已经包含图片链路需要的 `LIBLIB_*` 和 `TENCENT_COS_*` 配置项 + +### 仍需确认的点 + +- `TENCENT_COS_BUCKET` 和 `TENCENT_COS_BASE_URL` 是否为真正的生产资源 +- API 镜像和 Celery worker 是否会同步升级 +- 部署时是否一定会基于最新 `requirements.txt` 重新构建镜像 + +## 当前建议的上线结论 + +### 可以进入生产的前提 + +满足以下条件时,可以作为稳妥方案进入生产: + +1. 接受丢弃历史旧图 +2. 保持 `MEMOIR_IMAGE_ENABLED=false` +3. 使用最新镜像同时部署 `api` 与 `celery-worker` +4. 确认 COS 配置不是误填开发资源 + +### 不建议直接开启图片功能的场景 + +如果满足以下任一情况,建议不要在本次发版里直接启用图片生成: + +- 生产 COS bucket 尚未确认 +- Liblib 凭证未经生产验证 +- Celery worker 不会同步升级 +- 希望保留历史旧图但尚未做兼容或数据修复 + +## 最短上线检查单 + +发版前至少确认以下 5 项: + +1. `api/.env.production` 中 `MEMOIR_IMAGE_ENABLED` 是否符合本次上线策略 +2. `TENCENT_COS_BUCKET` / `TENCENT_COS_BASE_URL` 是否为生产资源 +3. `api` 和 `celery-worker` 是否会使用同一版新镜像 +4. 镜像是否会基于最新 `requirements.txt` 重建 +5. 团队是否明确接受“历史旧图可能消失” + +## 建议的发布策略 + +推荐分两步: + +### 第一步:保守上线 + +- 发布当前代码 +- `MEMOIR_IMAGE_ENABLED=false` +- 观察 API、WebSocket、章节读取、PDF 导出是否稳定 + +### 第二步:功能放量 + +- 确认 COS / Liblib / worker 正常 +- 再将 `MEMOIR_IMAGE_ENABLED=true` +- 仅对新生成章节启用图片功能 \ No newline at end of file