From a18a0b5c4f8a18c8e231227858ed0c50641ab26b Mon Sep 17 00:00:00 2001 From: aifoxman Date: Wed, 11 Mar 2026 05:35:23 -0700 Subject: [PATCH 1/4] init prod --- .github/workflows/docker-publish.yml | 152 ++++++++++++------------ .github/workflows/production-docker.yml | 138 +++++++++++++++++++++ .gitignore | 1 + Dockerfile | 2 +- Dockerfile.headed | 2 +- README.md | 10 +- config/setting.toml | 2 +- config/setting_example.toml | 2 +- docker-compose.headed.yml | 2 +- docker-compose.local.yml | 2 +- docker-compose.proxy.yml | 2 +- docker-compose.yml | 2 +- src/api/admin.py | 2 +- 13 files changed, 231 insertions(+), 88 deletions(-) create mode 100644 .github/workflows/production-docker.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 274cac6..036269b 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,77 +1,81 @@ -name: Build and Push Docker Image - on: push: branches: - - main - tags: - - 'v*' - pull_request: - branches: - - main - workflow_dispatch: - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - -jobs: - build-and-push: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - variant: standard - dockerfile: Dockerfile - image_suffix: "" - cache_scope: standard - - variant: headed - dockerfile: Dockerfile.headed - image_suffix: -headed - cache_scope: headed - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Container Registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.image_suffix }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=raw,value=latest,enable={{is_default_branch}} - - - name: Build and push Docker image (${{ matrix.variant }}) - uses: docker/build-push-action@v5 - with: - context: . - file: ${{ matrix.dockerfile }} - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=${{ matrix.cache_scope }} - cache-to: type=gha,mode=max,scope=${{ matrix.cache_scope }} + - "a-branch-that-will-never-exist-999" +#name: Build and Push Docker Image +# +#on: +# push: +# branches: +# - main +# tags: +# - "v*" +# pull_request: +# branches: +# - main +# workflow_dispatch: +# +#env: +# REGISTRY: ghcr.io +# IMAGE_NAME: ${{ github.repository }} +# +#jobs: +# build-and-push: +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# include: +# - variant: standard +# dockerfile: Dockerfile +# image_suffix: "" +# cache_scope: standard +# - variant: headed +# dockerfile: Dockerfile.headed +# image_suffix: -headed +# cache_scope: headed +# permissions: +# contents: read +# packages: write +# +# steps: +# - name: Checkout repository +# uses: actions/checkout@v4 +# +# - name: Set up QEMU +# uses: docker/setup-qemu-action@v3 +# +# - name: Set up Docker Buildx +# uses: docker/setup-buildx-action@v3 +# +# - name: Log in to Container Registry +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v3 +# with: +# registry: ${{ env.REGISTRY }} +# username: ${{ github.actor }} +# password: ${{ secrets.GITHUB_TOKEN }} +# +# - name: Extract metadata (tags, labels) +# id: meta +# uses: docker/metadata-action@v5 +# with: +# images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.image_suffix }} +# tags: | +# type=ref,event=branch +# type=ref,event=pr +# type=semver,pattern={{version}} +# type=semver,pattern={{major}}.{{minor}} +# type=raw,value=latest,enable={{is_default_branch}} +# +# - name: Build and push Docker image (${{ matrix.variant }}) +# uses: docker/build-push-action@v5 +# with: +# context: . +# file: ${{ matrix.dockerfile }} +# platforms: linux/amd64,linux/arm64 +# push: ${{ github.event_name != 'pull_request' }} +# tags: ${{ steps.meta.outputs.tags }} +# labels: ${{ steps.meta.outputs.labels }} +# cache-from: type=gha,scope=${{ matrix.cache_scope }} +# cache-to: type=gha,mode=max,scope=${{ matrix.cache_scope }} diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml new file mode 100644 index 0000000..4ea89cf --- /dev/null +++ b/.github/workflows/production-docker.yml @@ -0,0 +1,138 @@ +name: Build & Push +on: + push: + branches: + - main + +env: + REGISTRY: ghcr.io + USER_NAME: btcfoxman + IMAGE_NAME: flow2api + ALI_ENABLE: ${{ vars.ALI_ENABLE || 'true' }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + environment: SSH-JP + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version from src/main.py + id: version + run: | + python - <<'PY' + import os + import re + from pathlib import Path + + data = Path('src/main.py').read_text(encoding='utf-8') + m = re.search(r'version\s*=\s*["\']([^"\']+)["\']', data) + if not m: + raise SystemExit('version not found in src/main.py') + version = m.group(1) + output = os.environ.get("GITHUB_OUTPUT") + if output: + with open(output, "a", encoding="utf-8") as fh: + fh.write(f"version={version}\n") + print(f"version={version}") + PY + + - name: Build tag list + id: tags + run: | + GHCR_BASE="${{ env.REGISTRY }}/${{ env.USER_NAME }}/${{ env.IMAGE_NAME }}" + ALI_BASE="registry.cn-shenzhen.aliyuncs.com/epur/${{ env.IMAGE_NAME }}" + VERSION="v${{ steps.version.outputs.version }}" + + { + echo "value<> "$GITHUB_OUTPUT" + + - name: Login to Aliyun ACR + if: env.ALI_ENABLE == 'true' + uses: docker/login-action@v2 + with: + registry: registry.cn-shenzhen.aliyuncs.com + username: ${{ secrets.ALI_USERNAME }} + password: ${{ secrets.ALI_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.tags.outputs.value }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Deploy via SSH + uses: appleboy/ssh-action@v1.0.3 + env: + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} + GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} + GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} + DEPLOY_SERVICE: ${{ secrets.DEPLOY_SERVICE }} + ALI_ENABLE: ${{ env.ALI_ENABLE }} + ALI_USERNAME: ${{ secrets.ALI_USERNAME }} + ALI_PASSWORD: ${{ secrets.ALI_PASSWORD }} + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: ${{ secrets.DEPLOY_PORT }} + timeout: 60s + command_timeout: 20m + envs: DEPLOY_PATH,GHCR_TOKEN,GHCR_USERNAME,DEPLOY_SERVICE,ALI_ENABLE,ALI_USERNAME,ALI_PASSWORD + script: | + set -e + cd "$DEPLOY_PATH" + + if [ "$ALI_ENABLE" = "true" ]; then + echo "$ALI_PASSWORD" | docker login registry.cn-shenzhen.aliyuncs.com -u "$ALI_USERNAME" --password-stdin + IMAGE_REGISTRY="registry.cn-shenzhen.aliyuncs.com" + IMAGE_NAMESPACE="epur" + else + echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GHCR_USERNAME" --password-stdin + IMAGE_REGISTRY="ghcr.io" + IMAGE_NAMESPACE="btcfoxman" + fi + + touch .env + if grep -q '^IMAGE_REGISTRY=' .env; then + sed -i "s|^IMAGE_REGISTRY=.*|IMAGE_REGISTRY=${IMAGE_REGISTRY}|" .env + else + echo "IMAGE_REGISTRY=${IMAGE_REGISTRY}" >> .env + fi + + if grep -q '^IMAGE_NAMESPACE=' .env; then + sed -i "s|^IMAGE_NAMESPACE=.*|IMAGE_NAMESPACE=${IMAGE_NAMESPACE}|" .env + else + echo "IMAGE_NAMESPACE=${IMAGE_NAMESPACE}" >> .env + fi + + docker compose pull "$DEPLOY_SERVICE" + docker compose up -d "$DEPLOY_SERVICE" diff --git a/.gitignore b/.gitignore index 06035e2..63dcf5e 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ data config/setting.toml config/setting_warp.toml config/setting_warp_example.toml +.venv \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7a1c809..e797c5f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,6 @@ RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt COPY . . -EXPOSE 8000 +EXPOSE 4020 CMD ["python", "main.py"] diff --git a/Dockerfile.headed b/Dockerfile.headed index 7631427..523d3a6 100644 --- a/Dockerfile.headed +++ b/Dockerfile.headed @@ -27,6 +27,6 @@ COPY . . COPY docker/entrypoint.headed.sh /usr/local/bin/entrypoint.headed.sh RUN chmod +x /usr/local/bin/entrypoint.headed.sh -EXPOSE 8000 +EXPOSE 4020 CMD ["/usr/local/bin/entrypoint.headed.sh"] diff --git a/README.md b/README.md index 4dbc90c..46b5b59 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ python main.py ### 首次访问 -服务启动后,访问管理后台: **http://localhost:8000**,首次登录后请立即修改密码! +服务启动后,访问管理后台: **http://localhost:4020**,首次登录后请立即修改密码! - **用户名**: `admin` - **密码**: `admin` @@ -231,7 +231,7 @@ python main.py ### 文生图 ```bash -curl -X POST "http://localhost:8000/v1/chat/completions" \ +curl -X POST "http://localhost:4020/v1/chat/completions" \ -H "Authorization: Bearer han1234" \ -H "Content-Type: application/json" \ -d '{ @@ -249,7 +249,7 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \ ### 图生图 ```bash -curl -X POST "http://localhost:8000/v1/chat/completions" \ +curl -X POST "http://localhost:4020/v1/chat/completions" \ -H "Authorization: Bearer han1234" \ -H "Content-Type: application/json" \ -d '{ @@ -278,7 +278,7 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \ ### 文生视频 ```bash -curl -X POST "http://localhost:8000/v1/chat/completions" \ +curl -X POST "http://localhost:4020/v1/chat/completions" \ -H "Authorization: Bearer han1234" \ -H "Content-Type: application/json" \ -d '{ @@ -296,7 +296,7 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \ ### 首尾帧生成视频 ```bash -curl -X POST "http://localhost:8000/v1/chat/completions" \ +curl -X POST "http://localhost:4020/v1/chat/completions" \ -H "Authorization: Bearer han1234" \ -H "Content-Type: application/json" \ -d '{ diff --git a/config/setting.toml b/config/setting.toml index 1e9349b..7dc3537 100644 --- a/config/setting.toml +++ b/config/setting.toml @@ -12,7 +12,7 @@ max_poll_attempts = 200 [server] host = "0.0.0.0" -port = 8000 +port = 4020 [debug] enabled = false diff --git a/config/setting_example.toml b/config/setting_example.toml index 051cfd3..382a2c6 100644 --- a/config/setting_example.toml +++ b/config/setting_example.toml @@ -12,7 +12,7 @@ max_poll_attempts = 200 [server] host = "0.0.0.0" -port = 8000 +port = 4020 [debug] enabled = false diff --git a/docker-compose.headed.yml b/docker-compose.headed.yml index f521467..1f1ad43 100644 --- a/docker-compose.headed.yml +++ b/docker-compose.headed.yml @@ -8,7 +8,7 @@ services: image: flow2api:headed container_name: flow2api-headed ports: - - "8000:8000" + - "4020:4020" volumes: - ./data:/app/data - ./config/setting.toml:/app/config/setting.toml diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 8e55b4e..d52e3f3 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -8,7 +8,7 @@ services: image: flow2api:local container_name: flow2api ports: - - "38000:8000" + - "4020:4020" volumes: - ./data:/app/data - ./config/setting.toml:/app/config/setting.toml diff --git a/docker-compose.proxy.yml b/docker-compose.proxy.yml index 0cb3265..ff5bf0b 100644 --- a/docker-compose.proxy.yml +++ b/docker-compose.proxy.yml @@ -5,7 +5,7 @@ services: image: thesmallhancat/flow2api:latest container_name: flow2api ports: - - "38000:8000" + - "4020:4020" volumes: - ./data:/app/data - ./config/setting_warp.toml:/app/config/setting.toml diff --git a/docker-compose.yml b/docker-compose.yml index 60d2f1c..62ae7cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: image: ghcr.io/thesmallhancat/flow2api:latest container_name: flow2api ports: - - "38000:8000" + - "4020:4020" volumes: - ./data:/app/data - ./config/setting.toml:/app/config/setting.toml diff --git a/src/api/admin.py b/src/api/admin.py index 8a711f3..2177e1e 100644 --- a/src/api/admin.py +++ b/src/api/admin.py @@ -1118,7 +1118,7 @@ async def get_cache_config(token: str = Depends(verify_admin_token)): cache_config = await db.get_cache_config() # Calculate effective base URL - effective_base_url = cache_config.cache_base_url if cache_config.cache_base_url else f"http://127.0.0.1:8000" + effective_base_url = cache_config.cache_base_url if cache_config.cache_base_url else f"http://127.0.0.1:4020" return { "success": True, From 885d3e52f4b762095bddd2c921797211c5253f0c Mon Sep 17 00:00:00 2001 From: aifoxman Date: Wed, 11 Mar 2026 10:53:51 -0700 Subject: [PATCH 2/4] init prod --- .github/workflows/production-docker.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index 4ea89cf..44412aa 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -8,12 +8,13 @@ env: REGISTRY: ghcr.io USER_NAME: btcfoxman IMAGE_NAME: flow2api - ALI_ENABLE: ${{ vars.ALI_ENABLE || 'true' }} jobs: build-and-push: runs-on: ubuntu-latest environment: SSH-JP + env: + ALI_ENABLE: ${{ vars.ALI_ENABLE != '' && vars.ALI_ENABLE || 'true' }} permissions: contents: read packages: write @@ -25,6 +26,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Print ALI_ENABLE context + run: | + echo "environment=SSH-JP" + echo "vars.ALI_ENABLE=${{ vars.ALI_ENABLE }}" + echo "env.ALI_ENABLE=${{ env.ALI_ENABLE }}" + - name: Log in to GHCR uses: docker/login-action@v3 with: From 3af96cc023c13a066e028a9e6d135bf2aade3d36 Mon Sep 17 00:00:00 2001 From: aifoxman Date: Wed, 11 Mar 2026 11:01:36 -0700 Subject: [PATCH 3/4] init prod --- .github/workflows/production-docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index 44412aa..8bb5e27 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -141,5 +141,6 @@ jobs: echo "IMAGE_NAMESPACE=${IMAGE_NAMESPACE}" >> .env fi + docker network inspect my-shared-net >/dev/null 2>&1 || docker network create my-shared-net docker compose pull "$DEPLOY_SERVICE" docker compose up -d "$DEPLOY_SERVICE" From 506730478a47d63332b5d540d81c858b060551c3 Mon Sep 17 00:00:00 2001 From: aifoxman Date: Wed, 11 Mar 2026 12:08:16 -0700 Subject: [PATCH 4/4] init prod --- src/main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.py b/src/main.py index e301237..cff0342 100644 --- a/src/main.py +++ b/src/main.py @@ -235,3 +235,10 @@ async def manage_page(): if manage_file.exists(): return FileResponse(str(manage_file)) return HTMLResponse(content="

Management Page Not Found

", status_code=404) + + +@app.get("/health") +@app.get("/healthz") +async def health_check(): + """Basic liveness endpoint for container health checks.""" + return {"status": "ok"}