mirror of
https://github.com/TheSmallHanCat/flow2api.git
synced 2026-05-06 22:13:48 +08:00
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:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -54,3 +54,7 @@ logs.txt
|
||||
*.cache
|
||||
|
||||
browser_data
|
||||
|
||||
data
|
||||
config/setting.toml
|
||||
config/setting_warp.toml
|
||||
13
Dockerfile
13
Dockerfile
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
42
config/setting_example.toml
Normal file
42
config/setting_example.toml
Normal 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"
|
||||
42
config/setting_warp_example.toml
Normal file
42
config/setting_warp_example.toml
Normal 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
17
docker-compose.local.yml
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
36
src/main.py
36
src/main.py
@@ -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)
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
Reference in New Issue
Block a user