Files
life-echo/.github/workflows/docker-build-deploy.yml
penghanyuan 7fe0b70d5c feat: 增强对话代理以检测用户阶段并更新章节排序
- 在 api/agents/conversation_agent.py 中添加 _detect_user_stage 方法,以通过关键词检测用户谈论的人生阶段。
- 在 api/agents/memory_agent.py 中更新章节排序逻辑,使用 STAGE_TO_ORDER 替代 CHAPTER_ORDER。
- 在 api/agents/state_schema.py 中添加方法以获取各阶段的填充情况。
- 在 api/agents/prompts/conversation_prompts.py 中更新对话提示,包含用户阶段检测和整体进度信息。
- 在 api/migrations/fix_chapter_order_index.sql 中添加 SQL 脚本以修复章节 order_index 的问题。
- 更新相关文档和提示以反映新功能。
2026-02-13 21:45:56 +01:00

223 lines
8.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Docker Build and Deploy
on:
push:
branches:
- dev/add-agent
paths:
- 'api/**'
- '.github/workflows/**'
workflow_dispatch: # 允许手动触发
env:
IMAGE_NAME: lifecho-api
REGISTRY: crpi-u2903xccyzd6nqnc.cn-shanghai.personal.cr.aliyuncs.com
REGISTRY_NAMESPACE: huaga
jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Alibaba Cloud Container Registry
env:
REGISTRY: ${{ env.REGISTRY }}
USERNAME: ${{ secrets.ALIYUN_CR_USERNAME }}
PASSWORD: ${{ secrets.ALIYUN_CR_PASSWORD }}
run: |
echo "正在登录到阿里云容器镜像服务..."
echo "Registry: $REGISTRY"
echo "Username: $USERNAME"
echo "Password length: ${#PASSWORD}"
# 使用 printf 确保密码正确传递(包括特殊字符)
printf '%s\n' "$PASSWORD" | docker login "$REGISTRY" --username="$USERNAME" --password-stdin
echo "✅ 登录成功!"
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./api
file: ./api/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy to Remote Server
runs-on: ubuntu-latest
needs: build-and-push
if: github.event_name != 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H -p ${{ secrets.SSH_PORT || 22 }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Determine image tag
id: image_tag
run: |
if [ "${{ github.ref_name }}" == "main" ] || [ "${{ github.ref_name }}" == "master" ]; then
echo "tag=latest" >> $GITHUB_OUTPUT
else
# 将分支名中的斜杠替换为破折号,以符合 Docker 标签规范
BRANCH_TAG=$(echo "${{ github.ref_name }}" | sed 's/\//-/g')
echo "tag=$BRANCH_TAG" >> $GITHUB_OUTPUT
fi
- name: Deploy to remote server
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
IMAGE_TAG: ${{ env.REGISTRY }}/${{ env.REGISTRY_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ steps.image_tag.outputs.tag }}
COMPOSE_FILE: docker-compose.yml
COMPOSE_DIR: ${{ secrets.DEPLOY_PATH || '/opt/life-echo' }}
REGISTRY: ${{ env.REGISTRY }}
ALIYUN_CR_USERNAME: ${{ secrets.ALIYUN_CR_USERNAME }}
ALIYUN_CR_PASSWORD: ${{ secrets.ALIYUN_CR_PASSWORD }}
run: |
echo "开始部署到远程服务器..."
echo "镜像标签: $IMAGE_TAG"
echo "部署目录: $COMPOSE_DIR/api"
# 登录到阿里云容器仓库
echo "$ALIYUN_CR_PASSWORD" | ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"docker login $REGISTRY --username=$ALIYUN_CR_USERNAME --password-stdin"
# 创建部署目录(如果不存在)
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"mkdir -p $COMPOSE_DIR/api"
# 第一步:强制停止并删除所有旧容器
echo "停止并删除旧容器..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST "
# 先尝试使用 docker-compose down
cd $COMPOSE_DIR/api 2>/dev/null && docker-compose -f '$COMPOSE_FILE' down --remove-orphans 2>/dev/null || true
# 强制停止并删除所有 life-echo 相关容器(按名称匹配)
echo '强制清理所有 life-echo 容器...'
docker ps -a --filter 'name=life-echo' --format '{{.ID}}' | xargs -r docker rm -f 2>/dev/null || true
# 再次确保指定容器被删除
echo '确保指定容器被删除...'
docker rm -f life-echo-api-prod life-echo-celery-worker life-echo-postgres life-echo-redis life-echo-celery-beat life-echo-flower 2>/dev/null || true
# 等待容器完全停止
sleep 3
# 验证容器已删除
echo '验证容器状态...'
docker ps -a --filter 'name=life-echo' || true
"
# 第二步:先删除远程旧配置,再复制仓库中的 docker-compose.yml强制覆盖
echo "删除远程旧 docker-compose 配置以确保使用仓库版本..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"rm -f $COMPOSE_DIR/api/$COMPOSE_FILE $COMPOSE_DIR/api/${COMPOSE_FILE}.bak 2>/dev/null || true"
echo "复制配置文件(覆盖远程 docker-compose.yml..."
scp -P $SSH_PORT ./api/$COMPOSE_FILE $SSH_USER@$SSH_HOST:$COMPOSE_DIR/api/
# 复制 .env.production 到远程服务器(重命名为 .env.prod
echo "复制 .env.production 文件..."
scp -P $SSH_PORT ./api/.env.production $SSH_USER@$SSH_HOST:$COMPOSE_DIR/api/.env.prod
scp -P $SSH_PORT ./api/.env.production $SSH_USER@$SSH_HOST:$COMPOSE_DIR/api/.env.production
# 第三步:在远程服务器上执行部署操作
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST "
set -e
cd $COMPOSE_DIR/api
echo '拉取最新镜像: $IMAGE_TAG'
docker pull '$IMAGE_TAG' || true
echo '备份并更新 docker-compose.yml 中的镜像标签...'
cp '$COMPOSE_FILE' '${COMPOSE_FILE}.bak'
# 更新所有包含 lifecho-api 或 life-echo-api 的 image 行
sed -i.tmp 's|image:.*lifecho-api.*|image: $IMAGE_TAG|g' '$COMPOSE_FILE'
sed -i.tmp 's|image:.*life-echo-api.*|image: $IMAGE_TAG|g' '$COMPOSE_FILE'
# 清理临时文件
rm -f '${COMPOSE_FILE}.tmp' 2>/dev/null || true
echo '启动新容器...'
docker-compose -f '$COMPOSE_FILE' pull || true
docker-compose -f '$COMPOSE_FILE' up -d
echo '等待容器启动...'
sleep 15
echo '清理旧镜像...'
docker image prune -f || true
echo '部署完成!'
echo '检查容器状态...'
docker-compose -f '$COMPOSE_FILE' ps
"
- name: Run database migration
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
DB_USER: ${{ secrets.MIGRATION_DB_USER || 'postgres' }}
DB_NAME: ${{ secrets.MIGRATION_DB_NAME || 'life_echo' }}
run: |
echo "执行数据库结构同步迁移(幂等)..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"docker exec -i life-echo-postgres psql -U $DB_USER -d $DB_NAME" \
< api/migrations/sync_schema_to_models.sql
echo "修复章节 order_index..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"docker exec -i life-echo-postgres psql -U $DB_USER -d $DB_NAME" \
< api/migrations/fix_chapter_order_index.sql
echo "数据库迁移完成"
- name: Verify deployment
env:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
COMPOSE_DIR: ${{ secrets.DEPLOY_PATH || '/opt/life-echo' }}
run: |
echo "验证部署状态..."
ssh -p $SSH_PORT $SSH_USER@$SSH_HOST \
"cd $COMPOSE_DIR/api && docker-compose ps && docker-compose logs --tail=50 api"