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..8bb5e27 --- /dev/null +++ b/.github/workflows/production-docker.yml @@ -0,0 +1,146 @@ +name: Build & Push +on: + push: + branches: + - main + +env: + REGISTRY: ghcr.io + USER_NAME: btcfoxman + IMAGE_NAME: flow2api + +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 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - 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: + 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 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" diff --git a/.gitignore b/.gitignore index 4c133db..b9afbc2 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ tmp/ config/setting.toml config/setting_warp.toml config/setting_warp_example.toml + 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 c4112d4..2aec859 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ python main.py ### 首次访问 -服务启动后,访问管理后台: **http://localhost:8000**,首次登录后请立即修改密码! +服务启动后,访问管理后台: **http://localhost:4020**,首次登录后请立即修改密码! - **用户名**: `admin` - **密码**: `admin` @@ -302,7 +302,7 @@ curl -X POST "http://localhost:8000/models/gemini-3.1-flash-image:generateConten ### 文生图 ```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 '{ @@ -320,7 +320,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 '{ @@ -349,7 +349,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 '{ @@ -367,7 +367,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 949e662..2e125ee 100644 --- a/config/setting.toml +++ b/config/setting.toml @@ -26,7 +26,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 a02ad50..279b4e2 100644 --- a/config/setting_example.toml +++ b/config/setting_example.toml @@ -26,7 +26,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 dcf489d..2d51fa6 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 - ./tmp:/app/tmp diff --git a/docker-compose.local.yml b/docker-compose.local.yml index a7c8cad..039a6ec 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 - ./tmp:/app/tmp diff --git a/docker-compose.proxy.yml b/docker-compose.proxy.yml index 07b2221..d9a2ffc 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 - ./tmp:/app/tmp diff --git a/docker-compose.yml b/docker-compose.yml index ae005d0..08cdec6 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 - ./tmp:/app/tmp diff --git a/src/api/admin.py b/src/api/admin.py index a49b864..dd2dde2 100644 --- a/src/api/admin.py +++ b/src/api/admin.py @@ -1304,7 +1304,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, 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"}