数据库 - 新增迁移 0003:timeline_events.memory_source_id 外键 → memory_sources,便于按 ingest 源做时间线幂等 后端 - 记忆 - 新增 ingest 后 LLM 富化(摘要/事实/时间线),可配置开关与最大字符数 - 新增证据包组装:合并 chunk、摘要、事实、时间线、故事等检索结果;支持空 query 时是否仍带 rolling 等开关 - repo/retriever/service/router/schemas/summarizer/timeline/extractor 等扩展;文档 memory-retrieval.md 更新 后端 - 对话 WS - 增加 PING/PONG;分段 ASR 日志与空音频处理;转写失败与「无助手回复」错误提示更明确 - 助手多段回复持久化使用统一分隔符,与分段逻辑一致 后端 - Agent - reply_limits:按 [SPLIT] 与段落拆段,并保证非空 fallback,供 WS 与 TTS 多段下发 后端 - 回忆录任务 - transcript ingest 记录 source_id;任务成功结?
165 lines
6.7 KiB
YAML
165 lines
6.7 KiB
YAML
# 一次性:将旧 pg_dump 数据迁入当前 Alembic schema(api/scripts/migrate_legacy_to_current.py)
|
||
#
|
||
# 目标库须已是 alembic upgrade head(与线上一致);占号用户清理逻辑依赖当前全部迁移后的表结构。
|
||
#
|
||
# 不会在 push / 部署时自动运行,仅手动 workflow_dispatch,避免每次构建误迁库。
|
||
# 远端需已用 docker compose 部署(目录约定与 docker-build-deploy 一致:STAGING_DEPLOY_PATH / PROD_DEPLOY_PATH)。
|
||
#
|
||
# 备份文件:提交在仓库 api/backups/<dump_filename>(默认 life_echo_20260313_182756.sql),
|
||
# workflow 会先 scp 到远端再迁移。其他 *.sql 仍被 gitignore,需按需增加 ! 例外行。
|
||
#
|
||
# Secrets:与 Docker Build and Deploy 相同(STAGING_* / PROD_*)。
|
||
|
||
name: Legacy DB migrate (one-shot)
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
environment:
|
||
description: 'staging 或 production'
|
||
required: true
|
||
type: choice
|
||
options:
|
||
- staging
|
||
- production
|
||
confirm:
|
||
description: '确认执行迁移(必须完整输入 MIGRATE)'
|
||
required: true
|
||
type: string
|
||
dump_filename:
|
||
description: '仓库 api/backups/ 与远端同名 SQL 文件(须已提交)'
|
||
required: true
|
||
type: string
|
||
default: life_echo_20260313_182756.sql
|
||
recreate_legacy_database:
|
||
description: 'true=DROP 并重建 life_echo_legacy + 重新导入 SQL;false=仅运行迁移脚本'
|
||
required: true
|
||
type: boolean
|
||
default: true
|
||
|
||
concurrency:
|
||
group: legacy-migrate-${{ github.ref }}
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||
|
||
jobs:
|
||
migrate:
|
||
name: Legacy migrate on server
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- name: Require confirm MIGRATE
|
||
run: |
|
||
if [ "${{ github.event.inputs.confirm }}" != "MIGRATE" ]; then
|
||
echo "::error::确认字段必须精确为 MIGRATE,当前未执行任何操作"
|
||
exit 1
|
||
fi
|
||
|
||
- name: Checkout
|
||
uses: actions/checkout@v5
|
||
|
||
- name: Verify backup file in repo
|
||
env:
|
||
DUMP_FILENAME: ${{ github.event.inputs.dump_filename }}
|
||
run: |
|
||
set -euo pipefail
|
||
f="api/backups/$DUMP_FILENAME"
|
||
if [ ! -f "$f" ]; then
|
||
echo "::error::仓库中不存在 $f,请提交该文件或改正 dump_filename,并在 .gitignore 中为该文件增加 ! 例外"
|
||
exit 1
|
||
fi
|
||
ls -la "$f"
|
||
|
||
- name: Set up SSH (production)
|
||
if: github.event.inputs.environment == 'production'
|
||
uses: webfactory/ssh-agent@v0.9.1
|
||
with:
|
||
ssh-private-key: ${{ secrets.PROD_SSH_PRIVATE_KEY }}
|
||
|
||
- name: Set up SSH (staging)
|
||
if: github.event.inputs.environment != 'production'
|
||
uses: webfactory/ssh-agent@v0.9.1
|
||
with:
|
||
ssh-private-key: ${{ secrets.STAGING_SSH_PRIVATE_KEY }}
|
||
|
||
- name: Export deploy connection env
|
||
run: |
|
||
if [ "${{ github.event.inputs.environment }}" = "production" ]; then
|
||
{
|
||
echo "SSH_HOST=${{ secrets.PROD_SSH_HOST }}"
|
||
echo "SSH_USER=${{ secrets.PROD_SSH_USER }}"
|
||
echo "SSH_PORT=${{ secrets.PROD_SSH_PORT || '22' }}"
|
||
echo "COMPOSE_DIR=${{ secrets.PROD_DEPLOY_PATH || '/opt/life-echo' }}"
|
||
} >> "$GITHUB_ENV"
|
||
else
|
||
{
|
||
echo "SSH_HOST=${{ secrets.STAGING_SSH_HOST }}"
|
||
echo "SSH_USER=${{ secrets.STAGING_SSH_USER }}"
|
||
echo "SSH_PORT=${{ secrets.STAGING_SSH_PORT || '22' }}"
|
||
echo "COMPOSE_DIR=${{ secrets.STAGING_DEPLOY_PATH || '/opt/life-echo' }}"
|
||
} >> "$GITHUB_ENV"
|
||
fi
|
||
|
||
- name: Add server to known hosts
|
||
run: |
|
||
mkdir -p ~/.ssh
|
||
ssh-keyscan -H -p "${SSH_PORT:-22}" "${SSH_HOST}" >> ~/.ssh/known_hosts
|
||
|
||
- name: Upload dump to server
|
||
env:
|
||
DUMP_FILENAME: ${{ github.event.inputs.dump_filename }}
|
||
run: |
|
||
set -euo pipefail
|
||
ssh -p "$SSH_PORT" "$SSH_USER@$SSH_HOST" "mkdir -p \"$COMPOSE_DIR/api/backups\""
|
||
scp -P "$SSH_PORT" "api/backups/$DUMP_FILENAME" "$SSH_USER@$SSH_HOST:$COMPOSE_DIR/api/backups/$DUMP_FILENAME"
|
||
echo "已上传 api/backups/$DUMP_FILENAME -> $COMPOSE_DIR/api/backups/"
|
||
|
||
- name: Run legacy migrate on remote
|
||
env:
|
||
DUMP_FILENAME: ${{ github.event.inputs.dump_filename }}
|
||
RECREATE_LEGACY: ${{ github.event.inputs.recreate_legacy_database }}
|
||
run: |
|
||
set -euo pipefail
|
||
# 通过环境变量传入远端,避免 heredoc 引号问题
|
||
ssh -p "$SSH_PORT" "$SSH_USER@$SSH_HOST" \
|
||
"export COMPOSE_DIR=$(printf '%q' "$COMPOSE_DIR"); export DUMP_FILENAME=$(printf '%q' "$DUMP_FILENAME"); export RECREATE_LEGACY=$(printf '%q' "$RECREATE_LEGACY"); bash -s" << 'REMOTE'
|
||
set -euo pipefail
|
||
cd "$COMPOSE_DIR/api"
|
||
DUMP="$PWD/backups/$DUMP_FILENAME"
|
||
if [ ! -f "$DUMP" ]; then
|
||
echo "::error::远端缺少备份文件: $DUMP"
|
||
exit 1
|
||
fi
|
||
if [ ! -f .env ]; then
|
||
echo "::error::缺少 $PWD/.env"
|
||
exit 1
|
||
fi
|
||
# DATABASE_URL 可能含特殊字符,取第一个等号后的整行
|
||
DB_URL=$(grep -m1 '^DATABASE_URL=' .env | cut -d= -f2- | tr -d '\r' | sed 's/^"//;s/"$//;s/^'"'"'//;s/'"'"'$//')
|
||
PG_USER=$(grep -m1 '^POSTGRES_USER=' .env 2>/dev/null | cut -d= -f2- | tr -d '\r' | sed 's/^"//;s/"$//' || true)
|
||
PG_PASS=$(grep -m1 '^POSTGRES_PASSWORD=' .env 2>/dev/null | cut -d= -f2- | tr -d '\r' | sed 's/^"//;s/"$//' || true)
|
||
PG_USER=${PG_USER:-postgres}
|
||
PG_PASS=${PG_PASS:-postgres}
|
||
LEGACY_URL="postgresql://${PG_USER}:${PG_PASS}@postgres:5432/life_echo_legacy"
|
||
|
||
if [ "$RECREATE_LEGACY" = "true" ]; then
|
||
echo "重建 life_echo_legacy 并导入 SQL..."
|
||
docker compose exec -T postgres psql -U postgres -d postgres -v ON_ERROR_STOP=1 -c \
|
||
"DROP DATABASE IF EXISTS life_echo_legacy WITH (FORCE);"
|
||
docker compose exec -T postgres psql -U postgres -d postgres -v ON_ERROR_STOP=1 -c \
|
||
"CREATE DATABASE life_echo_legacy;"
|
||
docker exec -i life-echo-postgres psql -U postgres -d life_echo_legacy -v ON_ERROR_STOP=1 < "$DUMP"
|
||
else
|
||
echo "跳过 DROP/导入,假定 life_echo_legacy 已就绪"
|
||
fi
|
||
|
||
echo "执行 Python 迁移(api 容器内)..."
|
||
docker compose exec -T api uv run python scripts/migrate_legacy_to_current.py \
|
||
--legacy-url "$LEGACY_URL" \
|
||
--target-url "$DB_URL" \
|
||
--phone-conflict replace_target
|
||
echo "完成。"
|
||
REMOTE
|