feat: add auto-detection for headless environments and auto-switch captcha modes

- Add helper function to detect headless/Docker environments in main.py
- Implement auto-downgrade from personal to browser captcha mode in headless environments
- Show warning messages when switching modes automatically
- Update FlowClient to accept database instance for captcha configuration

config: update default server port and enable proxy by default

- Change default server port from 8000 to 18282 in config/setting.toml
- Enable proxy by default with localhost:7897 URL
- Update Docker and docker-compose configurations to use port 38000 for API

build: add China mirror sources for faster dependency installation

- Configure Debian apt to use Tsinghua University mirrors
- Set PyPI to use Tsinghua University index with trusted host
- Configure Playwright to download from npmmirror for faster installation

chore: update gitignore to exclude data and config files

- Add data directory to .gitignore
- Exclude config/setting.toml and config/setting_warp.toml from version control

docs: update docker-compose configurations for new port mappings

- Change exposed port from 8000 to 38000 in docker-compose.yml
- Update proxy service port from 1080 to 31080 in docker-compose.proxy.yml
- Ensure proper volume mapping for Cloudflare WARP data persistence
This commit is contained in:
Netlops
2025-12-30 14:00:30 +08:00
parent 35d960d238
commit c21f7708a6
10 changed files with 159 additions and 16 deletions

4
.gitignore vendored
View File

@@ -54,3 +54,7 @@ logs.txt
*.cache
browser_data
data
config/setting.toml
config/setting_warp.toml

View File

@@ -2,6 +2,10 @@ FROM python:3.11-slim
WORKDIR /app
# 使用清华镜像源加速 apt (Debian bookworm)
RUN sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources \
&& sed -i 's|security.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources
# 安装 Playwright 所需的系统依赖
RUN apt-get update && apt-get install -y \
libnss3 \
@@ -21,9 +25,14 @@ RUN apt-get update && apt-get install -y \
libcairo2 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
# 安装 Python 依赖(使用清华 PyPI 镜像)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir -r requirements.txt \
-i https://pypi.tuna.tsinghua.edu.cn/simple/ \
--trusted-host pypi.tuna.tsinghua.edu.cn
# 设置 Playwright 下载镜像(使用 npmmirror
ENV PLAYWRIGHT_DOWNLOAD_HOST=https://registry.npmmirror.com/-/binary/playwright
# 安装 Playwright 浏览器
RUN playwright install chromium

View File

@@ -12,7 +12,7 @@ max_poll_attempts = 200
[server]
host = "0.0.0.0"
port = 8000
port = 18282
[debug]
enabled = false
@@ -21,8 +21,8 @@ log_responses = true
mask_token = true
[proxy]
proxy_enabled = false
proxy_url = ""
proxy_enabled = true
proxy_url = "http://localhost:7897"
[generation]
image_timeout = 300

View File

@@ -0,0 +1,42 @@
[global]
api_key = "han1234"
admin_username = "admin"
admin_password = "admin"
[flow]
labs_base_url = "https://labs.google/fx/api"
api_base_url = "https://aisandbox-pa.googleapis.com/v1"
timeout = 120
poll_interval = 3.0
max_poll_attempts = 200
[server]
host = "0.0.0.0"
port = 18282
[debug]
enabled = false
log_requests = true
log_responses = true
mask_token = true
[proxy]
proxy_enabled = true
proxy_url = "http://localhost:7897"
[generation]
image_timeout = 300
video_timeout = 1500
[admin]
error_ban_threshold = 3
[cache]
enabled = false
timeout = 7200 # 缓存超时时间(秒), 默认2小时
base_url = "" # 缓存文件访问的基础URL, 留空则使用服务器地址
[captcha]
captcha_method = "browser" # 打码方式: yescaptcha 或 browser
yescaptcha_api_key = "" # YesCaptcha API密钥
yescaptcha_base_url = "https://api.yescaptcha.com"

View File

@@ -0,0 +1,42 @@
[global]
api_key = "han1234"
admin_username = "admin"
admin_password = "admin"
[flow]
labs_base_url = "https://labs.google/fx/api"
api_base_url = "https://aisandbox-pa.googleapis.com/v1"
timeout = 120
poll_interval = 3.0
max_poll_attempts = 200
[server]
host = "0.0.0.0"
port = 8000
[debug]
enabled = false
log_requests = true
log_responses = true
mask_token = true
[proxy]
proxy_enabled = true
proxy_url = "socks5://warp:1080"
[generation]
image_timeout = 300
video_timeout = 1500
[admin]
error_ban_threshold = 3
[cache]
enabled = false
timeout = 7200 # 缓存超时时间(秒), 默认2小时
base_url = "" # 缓存文件访问的基础URL, 留空则使用服务器地址
[captcha]
captcha_method = "browser" # 打码方式: yescaptcha 或 browser
yescaptcha_api_key = "" # YesCaptcha API密钥
yescaptcha_base_url = "https://api.yescaptcha.com"

17
docker-compose.local.yml Normal file
View File

@@ -0,0 +1,17 @@
version: '3.8'
services:
flow2api:
build:
context: .
dockerfile: Dockerfile
image: flow2api:local
container_name: flow2api
ports:
- "38000:8000"
volumes:
- ./data:/app/data
- ./config/setting.toml:/app/config/setting.toml
environment:
- PYTHONUNBUFFERED=1
restart: unless-stopped

View File

@@ -5,7 +5,7 @@ services:
image: thesmallhancat/flow2api:latest
container_name: flow2api
ports:
- "8000:8000"
- "38000:8000"
volumes:
- ./data:/app/data
- ./config/setting_warp.toml:/app/config/setting.toml
@@ -22,7 +22,7 @@ services:
devices:
- /dev/net/tun:/dev/net/tun
ports:
- "1080:1080"
- "31080:1080"
environment:
- WARP_SLEEP=2
cap_add:
@@ -33,4 +33,4 @@ services:
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv4.conf.all.src_valid_mark=1
volumes:
- ./data:/var/lib/cloudflare-warp
- ./data:/var/lib/cloudflare-warp

View File

@@ -5,7 +5,7 @@ services:
image: thesmallhancat/flow2api:latest
container_name: flow2api
ports:
- "8000:8000"
- "38000:8000"
volumes:
- ./data:/app/data
- ./config/setting.toml:/app/config/setting.toml

View File

@@ -68,18 +68,46 @@ async def lifespan(app: FastAPI):
# Load captcha configuration from database
captcha_config = await db.get_captcha_config()
config.set_captcha_method(captcha_config.captcha_method)
# Helper function to detect headless/Docker environment
def is_headless_environment() -> bool:
"""Check if running in a headless environment (Docker, no display, etc.)"""
import os
# Check for DISPLAY environment variable (X11)
if not os.environ.get("DISPLAY"):
# Check if running in Docker
if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_CONTAINER"):
return True
# Check for common CI/container indicators
if os.environ.get("CI") or os.environ.get("KUBERNETES_SERVICE_HOST"):
return True
# No DISPLAY and not explicitly local
return True
return False
# Determine effective captcha method
effective_captcha_method = captcha_config.captcha_method
# Auto-downgrade personal mode to browser mode in headless environments
if captcha_config.captcha_method == "personal" and is_headless_environment():
print("⚠️ WARNING: 'personal' captcha mode requires a display (X Server).")
print(" Detected headless environment (Docker/No Display).")
print(" Auto-switching to 'browser' (headless) mode.")
print(" To use 'personal' mode, run Flow2API on a machine with a display.")
effective_captcha_method = "browser"
config.set_captcha_method(effective_captcha_method)
config.set_yescaptcha_api_key(captcha_config.yescaptcha_api_key)
config.set_yescaptcha_base_url(captcha_config.yescaptcha_base_url)
# Initialize browser captcha service if needed
browser_service = None
if captcha_config.captcha_method == "personal":
if effective_captcha_method == "personal":
from .services.browser_captcha_personal import BrowserCaptchaService
browser_service = await BrowserCaptchaService.get_instance(db)
await browser_service.open_login_window()
print("✓ Browser captcha service initialized (webui mode)")
elif captcha_config.captcha_method == "browser":
elif effective_captcha_method == "browser":
from .services.browser_captcha import BrowserCaptchaService
browser_service = await BrowserCaptchaService.get_instance(db)
print("✓ Browser captcha service initialized (headless mode)")
@@ -135,7 +163,7 @@ async def lifespan(app: FastAPI):
# Initialize components
db = Database()
proxy_manager = ProxyManager(db)
flow_client = FlowClient(proxy_manager)
flow_client = FlowClient(proxy_manager, db)
token_manager = TokenManager(db, flow_client)
concurrency_manager = ConcurrencyManager()
load_balancer = LoadBalancer(token_manager, concurrency_manager)

View File

@@ -12,8 +12,9 @@ from ..core.config import config
class FlowClient:
"""VideoFX API客户端"""
def __init__(self, proxy_manager):
def __init__(self, proxy_manager, db=None):
self.proxy_manager = proxy_manager
self.db = db # Database instance for captcha config
self.labs_base_url = config.flow_labs_base_url # https://labs.google/fx/api
self.api_base_url = config.flow_api_base_url # https://aisandbox-pa.googleapis.com/v1
self.timeout = config.flow_timeout
@@ -691,7 +692,7 @@ class FlowClient:
if captcha_method == "personal":
try:
from .browser_captcha_personal import BrowserCaptchaService
service = await BrowserCaptchaService.get_instance(self.proxy_manager)
service = await BrowserCaptchaService.get_instance(self.db)
return await service.get_token(project_id)
except Exception as e:
debug_logger.log_error(f"[reCAPTCHA Browser] error: {str(e)}")
@@ -700,7 +701,7 @@ class FlowClient:
elif captcha_method == "browser":
try:
from .browser_captcha import BrowserCaptchaService
service = await BrowserCaptchaService.get_instance(self.proxy_manager)
service = await BrowserCaptchaService.get_instance(self.db)
return await service.get_token(project_id)
except Exception as e:
debug_logger.log_error(f"[reCAPTCHA Browser] error: {str(e)}")