* add staging ios app build script * feat(api): add OpenTelemetry LGTM stack for local observability Wire OTel traces, metrics, and logs through a collector to Tempo, Prometheus, and Loki, with custom LLM instrumentation, dev compose overlay, Grafana provisioning, env templates, and development.sh auto-start. Co-authored-by: Cursor <cursoragent@cursor.com> * feat: expand observability, harden dev tooling, and fix expo staging UX Add business and LLM Prometheus metrics with Grafana dashboards, alerting, and a metrics verification script. Wire telemetry through adapters and core LLM paths, and document the local LGTM workflow. Fix development.sh for macOS bash 3.2, open Grafana and eval-web in Chrome, and repair eval-web auto-open (unbound EVAL_WEB_BROWSER_SCHEDULED). Merge internal-eval into the main dev script with improved compose handling. Require EXPO_PUBLIC_* at build time, improve iOS HTTP ATS for staging IPs, show memoir empty state instead of load errors when no chapters exist, and add jest env setup plus chapter list response normalization. Co-authored-by: Cursor <cursoragent@cursor.com> * chore: enable Grafana Assistant Cursor plugin Co-authored-by: Cursor <cursoragent@cursor.com> * fix: memoir empty state and repair withdrawn 0020_chapters_book_id stamp Show empty memoir UI when the chapter list succeeds with no items; treat auth/404 as non-fatal. Extend alembic revision repair so local dev DBs stamped with the removed 0020_chapters_book_id migration can roll back and upgrade to 0019. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Kevin <kevin@brighteng.org> Co-authored-by: Cursor <cursoragent@cursor.com>
353 lines
18 KiB
Plaintext
353 lines
18 KiB
Plaintext
# =============================================================================
|
||
# Life Echo API — 模板(example)
|
||
#
|
||
# 目录结构与 api/.env.development 对齐,便于对照;占位键见各段注释。
|
||
# 本地:复制为 .env.development(勿提交密钥),再运行 api/development.sh 会在首次自动生成 .env(从
|
||
# .env.development 复制);Settings 只读 .env(见 app/core/config.py)。
|
||
# 服务端:仓库维护 .env.staging / .env.production;workflow 按目标环境上传并复制为运行时 .env,compose 的 env_file 统一指向 .env。
|
||
# 不要把真实密钥提交到仓库。
|
||
# =============================================================================
|
||
|
||
# =============================================================================
|
||
# Docker Compose(宿主机独立 Caddy 反代到本 API)
|
||
# =============================================================================
|
||
# 映射到宿主机的端口:不设置则由 Docker 随机分配,避免与同机其它项目冲突;随机时用 `docker compose port api 8000` 查看。
|
||
# 需固定端口时取消下行注释并改为未占用端口,Caddyfile 中 reverse_proxy 到 127.0.0.1:该端口。
|
||
# LIFE_ECHO_API_HOST_PORT=8000
|
||
# 若 Caddy 跑在独立容器且非 host 网络,不要用 127.0.0.1,应把 Caddy 加入与本 compose 相同的 Docker 网络,并对 http://life-echo-api-prod:8000 做 reverse_proxy。
|
||
|
||
# =============================================================================
|
||
# OpenTelemetry(见 docs/observability.md;Settings 只读 .env,勿 shell export)
|
||
# =============================================================================
|
||
# docker-compose.observability.yml 宿主机端口(高位口,避免 3000/9090/4317 冲突)
|
||
# GRAFANA_HOST_PORT=48300
|
||
# PROMETHEUS_HOST_PORT=49090
|
||
# OTEL_GRPC_HOST_PORT=48317
|
||
# OTEL_HTTP_HOST_PORT=48318
|
||
# OTEL_COLLECTOR_HEALTH_HOST_PORT=48333
|
||
# TEMPO_HTTP_HOST_PORT=43200
|
||
# LOKI_HTTP_HOST_PORT=43100
|
||
#
|
||
# --- development(.env.development):本机 uvicorn/celery ---
|
||
# OTEL_ENABLED=true
|
||
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:48317
|
||
# OTEL_TRACES_SAMPLER=always_on
|
||
#
|
||
# --- staging / production(.env.staging / .env.production):容器内 compose ---
|
||
# OTEL_ENABLED=false
|
||
# OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
|
||
# OTEL_TRACES_SAMPLER=parentbased_traceidratio
|
||
# OTEL_TRACES_SAMPLER_ARG=0.1
|
||
#
|
||
OTEL_ENABLED=true
|
||
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:48317
|
||
OTEL_EXPORTER_OTLP_INSECURE=true
|
||
OTEL_SERVICE_NAME=life-echo-api
|
||
OTEL_TRACES_SAMPLER=always_on
|
||
# OTEL_TRACES_SAMPLER_ARG=0.1
|
||
# OTEL_METRIC_EXPORT_INTERVAL_MS=10000
|
||
|
||
# =============================================================================
|
||
# Logging(loguru sink 最低级别:TRACE / DEBUG / INFO / WARNING / ERROR / CRITICAL)
|
||
# =============================================================================
|
||
# 生产/预发:保持 INFO,避免 DEBUG 把全文 prompt/响应打进日志。排查 Agent 耗时可仅开 LOG_AGENT_VERBOSE。
|
||
LOG_LEVEL=INFO
|
||
# Agent 单行 INFO 摘要(耗时、sha、字符数);与 LOG_LEVEL 独立,生产可短时设为 1
|
||
# LOG_AGENT_VERBOSE=0
|
||
# DEBUG 下 prompt/响应预览最大字符数(Settings 默认 4096);0=不截断全文(慎用)
|
||
# AGENT_LOG_MAX_CHARS=4096
|
||
# DEBUG 下 *.prompt:preview=截断预览 | hash_only=仅 sha12+长度,无正文
|
||
# AGENT_LOG_PROMPT_MODE=preview
|
||
# DEBUG 下同一 label 连续相同 prompt 则跳过重复行(减模板重复)
|
||
# AGENT_LOG_PROMPT_DEDUP=0
|
||
# DEBUG 下访谈/资料:省略 SystemMessage 正文(仅 total_len+sha12);0/false=打出全文
|
||
# AGENT_LOG_OMIT_SYSTEM_MESSAGE_BODY=1
|
||
# DEBUG 下超长单段 *.prompt:总长超过下一项时,先跳过前 N 字符再预览(0=不跳过;短时 DEBUG 可设 2500–8000)
|
||
# AGENT_LOG_JSON_PROMPT_PREFIX_CHARS=0
|
||
# AGENT_LOG_JSON_PROMPT_PREFIX_ONLY_IF_LEN_GT=4000
|
||
# 第三方 stdlib logging(空=自动:LOG_LEVEL 为 DEBUG/TRACE 时 Celery→INFO;否则 Celery 与 httpx 默认 WARNING;需原始框架行时设为 INFO)
|
||
# CELERY_LOG_LEVEL=
|
||
# HTTPX_LOG_LEVEL=
|
||
# 聚合用 JSONL(空=不写);与 stderr 并存,loguru serialize=True、按 20MB 切割、保留 7 天
|
||
# LOG_JSON_FILE=/var/log/life-echo/app.jsonl
|
||
|
||
# =============================================================================
|
||
# LLM / DeepSeek
|
||
# =============================================================================
|
||
DEEPSEEK_API_KEY=your_deepseek_api_key
|
||
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||
# 官方新模型名见 https://api-docs.deepseek.com/zh-cn/quick_start/pricing
|
||
DEEPSEEK_MODEL=deepseek-v4-flash
|
||
# v4-flash 主链路非思考须显式关(对齐旧版 deepseek-chat;默认 false)
|
||
# DEEPSEEK_THINKING_ENABLED=false
|
||
|
||
# =============================================================================
|
||
# Memory 向量(智谱 BigModel 国内 embedding-3;与 DeepSeek/OpenAI 用途分离)
|
||
# 文档:https://docs.bigmodel.cn/cn/guide/models/embedding/embedding-3
|
||
# 本期固定 1024 维;库表经迁移与 MEMORY_EMBEDDING_DIMENSION 一致。
|
||
# =============================================================================
|
||
ZHIPU_API_KEY=your_zhipu_api_key
|
||
# 默认国内通用端点(与 ZhipuAiClient 一致)
|
||
# EMBEDDING_BASE_URL=https://open.bigmodel.cn/api/paas/v4
|
||
EMBEDDING_MODEL=embedding-3
|
||
|
||
# Chat 访谈:每轮根据用户内容判定主人生阶段(关则仅用关键词,省一次 LLM)
|
||
# CHAT_STAGE_DETECTION_ENABLED=true
|
||
# CHAT_STAGE_DETECTION_MAX_TOKENS=128
|
||
# 年代/流行文化联想块(config 默认 true;若减少「文艺硬接」可设 false)
|
||
# CHAT_ERA_CONTEXT_ENABLED=true
|
||
# 访谈性格(InterviewAgent):default | warm_listener | curious_guide(config 默认 default)
|
||
# CHAT_INTERVIEW_PERSONA=default
|
||
# 访谈回复长度档位(brief/standard/expanded)联动:极短输入 / 默认 / 长段+新细节(若与当前代码不一致以 config 为准)
|
||
# CHAT_INTERVIEW_BRIEF_MAX_TOKENS=240
|
||
# CHAT_INTERVIEW_BRIEF_MAX_CHARS_PER_SEGMENT=180
|
||
# CHAT_INTERVIEW_EXPANDED_MAX_TOKENS=400
|
||
# CHAT_INTERVIEW_EXPANDED_MAX_CHARS_PER_SEGMENT=300
|
||
# 访谈/开场采样温度(config 默认 0.93;偏「好访谈者」体验时可试 0.60~0.70)
|
||
# CHAT_INTERVIEW_TEMPERATURE=0.93
|
||
# 访谈主回复:统一 max_tokens / 单段字数(代码截断)
|
||
# CHAT_INTERVIEW_MAX_TOKENS=512
|
||
# CHAT_INTERVIEW_MAX_CHARS_PER_SEGMENT=380
|
||
# CHAT_INTERVIEW_MAX_SEGMENTS=2
|
||
# 访谈:是否按本轮用户话检索记忆并注入提示词(关则不调 retrieve)
|
||
# CHAT_MEMORY_RETRIEVAL_ENABLED=true
|
||
# CHAT_MEMORY_TOP_K=8
|
||
# CHAT_MEMORY_EVIDENCE_MAX_CHARS=4096
|
||
# 规则 TurnPlan 之后再调一轮 JSON focus planner(config 默认 false;开启则多一次 LLM)
|
||
# CHAT_REPLY_PLANNER_LLM_ENABLED=true
|
||
# CHAT_REPLY_PLANNER_MAX_TOKENS=256
|
||
# CHAT_REPLY_PLANNER_TEMPERATURE=0.2
|
||
|
||
# Memoir:批处理/抽取更新 slot 时是否允许改写 MemoirState.current_stage(默认 false,访谈 switch_stage 仍可推进)
|
||
# True 时仅当 proposed 与 existing 在同一 chat_bucket 才对齐 current_stage
|
||
# MEMOIR_EXTRACTION_UPDATES_CURRENT_STAGE=false
|
||
|
||
# Memoir:叙事前口述归一(segment 原文仍落库;仅 story 流水线派生输入)
|
||
# MEMOIR_ORAL_NORMALIZE_ENABLED=true
|
||
# off | rules | llm(llm 为先规则再 LLM 纠错,失败回退规则结果)
|
||
# MEMOIR_ORAL_NORMALIZE_MODE=llm
|
||
# MEMOIR_ORAL_NORMALIZE_LLM_MAX_TOKENS=512
|
||
# MEMOIR_ORAL_NORMALIZE_LLM_MAX_INPUT_CHARS=8000
|
||
|
||
# Chat:模型消费净稿(segment 原文仍落库;访谈编排层归一后注入 Agent / 记忆检索)
|
||
# CHAT_INPUT_NORMALIZE_ENABLED=true
|
||
# off | rules | llm(llm 为先规则再 LLM;失败回退规则;编排层已带 LLM 时不重复在 Agent 调)
|
||
# CHAT_INPUT_NORMALIZE_MODE=rules
|
||
# CHAT_INPUT_NORMALIZE_LLM_MAX_TOKENS=512
|
||
# CHAT_INPUT_NORMALIZE_LLM_MAX_INPUT_CHARS=8000
|
||
# True:仅 is_from_voice 时走 LLM 纠错;键盘输入仅规则归一
|
||
# CHAT_INPUT_NORMALIZE_LLM_VOICE_ONLY=true
|
||
|
||
# Memoir Phase1:True 时用一次「批量 JSON」做抽取+分类(单段或多段均可;失败自动回退逐段)。
|
||
# False 时始终逐段(与启用本开关前的行为一致,含防抖合并后的多段任务)。
|
||
# MEMOIR_PHASE1_BATCH_LLM_ENABLED=false
|
||
# MEMOIR_PHASE1_BATCH_LLM_MAX_TOKENS=4096
|
||
|
||
# =============================================================================
|
||
# Database
|
||
# =============================================================================
|
||
# 本地开发(docker-compose.dev.yml 固定宿主端口 48291,避免与本机 5432 冲突)
|
||
# DATABASE_URL=postgresql://postgres:postgres@localhost:48291/life_echo
|
||
# Docker / 服务端(主机名一般为 compose 服务名 postgres):
|
||
# DATABASE_URL=postgresql://postgres:postgres@postgres:5432/life_echo
|
||
DATABASE_URL=postgresql://postgres:postgres@localhost:48291/life_echo
|
||
# 启动时 Alembic(main.py);生产可设 ALEMBIC_STARTUP_FAIL_FAST=true,迁移失败则拒绝启动
|
||
# ALEMBIC_RUN_ON_STARTUP=true
|
||
# ALEMBIC_STARTUP_FAIL_FAST=false
|
||
# ALEMBIC_STARTUP_MAX_RETRIES=3
|
||
# ALEMBIC_STARTUP_RETRY_BASE_SECONDS=1.0
|
||
|
||
# =============================================================================
|
||
# Redis
|
||
# =============================================================================
|
||
# 本地开发(docker-compose.dev.yml 固定宿主端口 48307,避免与本机 6379 冲突)
|
||
# REDIS_URL=redis://localhost:48307/0
|
||
# Docker / 服务端:
|
||
# REDIS_URL=redis://redis:6379/0
|
||
REDIS_URL=redis://localhost:48307/0
|
||
REDIS_SESSION_TTL=86400
|
||
|
||
# Celery:ingest 后 Memory LLM 富化任务投递队列(须被 worker 消费;见 README)
|
||
# CELERY_MEMORY_ENRICHMENT_QUEUE=memory_idle
|
||
|
||
# =============================================================================
|
||
# Internal evaluation API(internal_main;development.sh 默认一并启动;与主 API 进程隔离)
|
||
# =============================================================================
|
||
# 本地:`openssl rand -hex 32`;不用 internal eval 时可留空
|
||
INTERNAL_EVAL_API_KEY=
|
||
# INTERNAL_EVAL_ENABLE_DOCS=1
|
||
# 评测台选 DeepSeek 评审:默认 deepseek-v4-flash + 非思考(与 https://api-docs.deepseek.com/zh-cn/quick_start/pricing 一致)
|
||
# EVAL_JUDGE_DEEPSEEK_MODEL=deepseek-v4-flash
|
||
# 仅写 v4-flash 模型 id 时是否启用思考(弃用名 deepseek-reasoner 仍始终为思考)
|
||
# EVAL_JUDGE_DEEPSEEK_THINKING_ENABLED=false
|
||
|
||
# =============================================================================
|
||
# Memory compaction(近重复 memory chunk 软排除;Celery + Redis 防抖)
|
||
# 模板统一默认开启;须同时运行 celery worker 与 celery-beat(docker-compose 已含 beat,负责 memory_compaction_sweep)。
|
||
# =============================================================================
|
||
MEMORY_COMPACTION_ENABLED=true
|
||
# MEMORY_COMPACTION_DEBOUNCE_SECONDS=105
|
||
# MEMORY_COMPACTION_LOCK_TTL_SECONDS=600
|
||
# MEMORY_COMPACTION_CHUNK_SIMILARITY_THRESHOLD=0.92
|
||
# MEMORY_COMPACTION_MIN_LAYERS_FOR_EXCLUDE=2
|
||
# MEMORY_COMPACTION_MAX_CHUNKS_PER_RUN=200
|
||
# MEMORY_COMPACTION_MAX_EXCLUDES_PER_RUN=50
|
||
# MEMORY_COMPACTION_MAX_NEIGHBORS_PER_CHUNK=25
|
||
# MEMORY_COMPACTION_TEXT_JACCARD_MIN=0.55
|
||
# MEMORY_COMPACTION_METADATA_EVENT_YEAR_WINDOW=1
|
||
# MEMORY_COMPACTION_SWEEP_RECENT_HOURS=24
|
||
|
||
# =============================================================================
|
||
# Story 流水线(post-commit、章节物化、append 上限、evidence 检索)
|
||
# =============================================================================
|
||
# STORY_IMAGE_ENQUEUE_DEDUP_TTL=300
|
||
# RECOMPOSE_CHAPTER_DELAY_SECONDS=8
|
||
# CHAPTER_PIPELINE_LOCK_TTL_SECONDS=120
|
||
# STORY_APPEND_MAX_CANONICAL_CHARS=12000
|
||
# STORY_APPEND_MAX_VERSIONS=20
|
||
# EVIDENCE_TOP_K_DEFAULT=10
|
||
# EVIDENCE_TOP_K_LARGE_BATCH=5
|
||
# EVIDENCE_LARGE_BATCH_THRESHOLD=3
|
||
#
|
||
# Memoir 可靠性(叙事 faithful、标题 slots、证据渗漏、Phase1→2 追踪)
|
||
# MEMOIR_FIDELITY_FAIL_OPEN_ON_PARSE_ERROR=false
|
||
# MEMOIR_NARRATIVE_EVIDENCE_OVERLAP_MIN_CHARS=14
|
||
# MEMOIR_EVIDENCE_SCENE_ANCHOR_CHECK_ENABLED=true
|
||
# MEMOIR_TITLE_SLOTS_REQUIRE_BODY_OR_ORAL_MATCH=true
|
||
# MEMOIR_TITLE_HAY_GROUNDING_STRICT_PHRASES_ENABLED=true
|
||
# MEMOIR_RECOMPOSE_RETRY_ON_LOCK_CONTENTION=true
|
||
# MEMOIR_PHASE2_SINGLEFLIGHT_IMMEDIATE=true
|
||
#
|
||
# =============================================================================
|
||
# Auth
|
||
# =============================================================================
|
||
# 建议使用: openssl rand -hex 32
|
||
SECRET_KEY=replace_with_a_strong_random_secret
|
||
ALGORITHM=HS256
|
||
ACCESS_TOKEN_EXPIRE_MINUTES=120
|
||
# 内网评测:开启后可用 POST /api/auth/mock/sms-login(跳过短信);APP_ENV=production 时该路由仍返回 404
|
||
# MOCK_SMS_LOGIN_ENABLED=1
|
||
|
||
# =============================================================================
|
||
# Tencent Cloud — 短信
|
||
# =============================================================================
|
||
# 短信、一句话 ASR/TTS、COS 为不同产品;同一主账号可共用同一对 SecretId/SecretKey(分别填三处)。
|
||
TENCENT_SMS_SECRET_ID=your_tencent_sms_secret_id
|
||
TENCENT_SMS_SECRET_KEY=your_tencent_sms_secret_key
|
||
# 短信应用 SDK AppID
|
||
TENCENT_SMS_SDK_APP_ID=your_sms_sdk_app_id
|
||
# 短信签名内容(不包含【】符号)
|
||
TENCENT_SMS_SIGN_NAME=your_sms_sign_name
|
||
# 短信模板 ID
|
||
TENCENT_SMS_TEMPLATE_ID=your_sms_template_id
|
||
# 短信模板参数数量(1=仅验证码,2=验证码+过期时间)
|
||
# 若遇 TemplateParamSetNotMatchApprovedTemplate,请对照控制台模板配置
|
||
TENCENT_SMS_TEMPLATE_PARAM_COUNT=1
|
||
|
||
# =============================================================================
|
||
# ASR Provider(whisper | tencent)
|
||
# =============================================================================
|
||
ASR_PROVIDER=whisper
|
||
|
||
# =============================================================================
|
||
# Whisper ASR(ASR_PROVIDER=whisper 时使用)
|
||
# =============================================================================
|
||
ASR_MODEL_SIZE=small
|
||
ASR_DEVICE=cpu
|
||
ASR_COMPUTE_TYPE=int8
|
||
|
||
# GPU 环境(示例,按需启用)
|
||
# ASR_MODEL_SIZE=medium
|
||
# ASR_DEVICE=cuda
|
||
# ASR_COMPUTE_TYPE=float16
|
||
|
||
# =============================================================================
|
||
# Tencent Cloud — 一句话 ASR + TTS(ASR_PROVIDER=tencent 或 TTS_PROVIDER=tencent)
|
||
# =============================================================================
|
||
TENCENT_SECRET_ID=your_tencent_asr_secret_id
|
||
TENCENT_SECRET_KEY=your_tencent_asr_secret_key
|
||
|
||
# =============================================================================
|
||
# TTS(文字转语音,Agent 回复朗读)— 与 ASR 独立
|
||
# =============================================================================
|
||
# ENABLE_TTS:关闭时禁用「助手每轮自动生成 TTS」(tts_this_turn 链路);不影响 WebSocket「按需朗读」tts_request。
|
||
# 每轮是否自动生成:客户端 `data.tts_this_turn`,且 ENABLE_TTS=true、skeleton skip_tts 均未阻止时才会合成。
|
||
ENABLE_TTS=true
|
||
TTS_PROVIDER=tencent
|
||
# 仅 TTS_PROVIDER=openai 时需要
|
||
# OPENAI_API_KEY=
|
||
# 音色 ID 见 https://cloud.tencent.com/document/product/1073/92668
|
||
TTS_VOICE_TYPE=501004
|
||
TTS_CODEC=mp3
|
||
|
||
# =============================================================================
|
||
# 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
|
||
# 商户私钥:推荐使用文件路径,避免 .env 中长 PEM 转义问题
|
||
WECHAT_PAY_PRIVATE_KEY_PATH=certs/apiclient_key.pem
|
||
# 若不用文件,可配置 WECHAT_PAY_PRIVATE_KEY(PEM,换行用 \n)
|
||
# WECHAT_PAY_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
||
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=
|
||
ALIPAY_PRIVATE_KEY=
|
||
ALIPAY_PUBLIC_KEY=
|
||
ALIPAY_NOTIFY_URL=https://your-domain.com/api/payment/notify/alipay
|
||
|
||
# =============================================================================
|
||
# Misc
|
||
# =============================================================================
|
||
ENABLE_TEST_SUBSCRIPTION=0
|
||
|
||
# =============================================================================
|
||
# Memoir image generation(Story 主图等;轮询 Liblib 任务)
|
||
# =============================================================================
|
||
MEMOIR_IMAGE_ENABLED=false
|
||
MEMOIR_IMAGE_POLL_INTERVAL=3
|
||
MEMOIR_IMAGE_MAX_ATTEMPTS=20
|
||
MEMOIR_IMAGE_PROVIDER=liblib
|
||
MEMOIR_IMAGE_STYLE_DEFAULT=watercolor
|
||
MEMOIR_IMAGE_SIZE_DEFAULT=1280x720
|
||
# 章节正文内至少多少张 asset:// 插图才生成/展示章节封面(默认 1=有一张正文图即可)
|
||
MEMOIR_MIN_INLINE_IMAGES_FOR_CHAPTER_COVER=1
|
||
# Story 正文至少多少字才生成主图 intent / 调图(0=不限制)
|
||
STORY_IMAGE_MIN_BODY_CHARS=400
|
||
# 叙事模型输出相对口述过短则回退为口述原文
|
||
MEMOIR_NARRATIVE_FALLBACK_BODY_RATIO=0.5
|
||
MEMOIR_NARRATIVE_FALLBACK_MIN_CHARS=20
|
||
# 回忆录 segment 入队:累计 strip 后字数未达此值则暂缓提交 Celery(0=关闭字数门闸,仅静默防抖后提交)
|
||
# MEMOIR_SEGMENT_BATCH_MIN_CHARS=50
|
||
# 本批首条入队起最长等待(秒),超时仍提交;测试可调低,生产可调高
|
||
# MEMOIR_SEGMENT_BATCH_MAX_WAIT_SECONDS=60
|
||
# 可选,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 Cloud — COS(回忆录图片存储)
|
||
# =============================================================================
|
||
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_bucket_name
|
||
TENCENT_COS_BASE_URL=https://your_bucket_name.cos.ap-shanghai.myqcloud.com
|
||
# 可选临时凭证
|
||
# TENCENT_COS_TOKEN=
|