Skip to content

Commit e882317

Browse files
committed
feat(models): 支持 Veo 3.1 短时长放大与 YesCaptcha 类型配置
1 parent 9f1d712 commit e882317

13 files changed

Lines changed: 565 additions & 73 deletions

README.md

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
- 由于Flow增加了额外的验证码,你可以自行选择使用浏览器打码或第三发打码:
3636
注册[YesCaptcha](https://yescaptcha.com/i/13Xd8K)并获取api key,将其填入系统配置页面```YesCaptcha API密钥```区域
37+
- YesCaptcha 支持在管理页切换 `type``RecaptchaV3TaskProxyless``RecaptchaV3TaskProxylessM1``RecaptchaV3TaskProxylessM1S7``RecaptchaV3TaskProxylessM1S9`;S7/S9 会强制提交 `minScore` 0.7/0.9。
3738
- 默认 `docker-compose.yml` 建议搭配第三方打码(yescaptcha/capmonster/ezcaptcha/capsolver)。
3839
如需 Docker 内有头打码(browser/personal),请使用下方 `docker-compose.headed.yml`
3940

@@ -138,8 +139,6 @@ Prometheus 可直接抓 `/metrics`。如果部署到 Kubernetes,建议只在
138139

139140
| 模型名称 | 说明| 尺寸 |
140141
|---------|--------|--------|
141-
| `gemini-2.5-flash-image-landscape` | 图/文生图 | 横屏 |
142-
| `gemini-2.5-flash-image-portrait` | 图/文生图 | 竖屏 |
143142
| `gemini-3.0-pro-image-landscape` | 图/文生图 | 横屏 |
144143
| `gemini-3.0-pro-image-portrait` | 图/文生图 | 竖屏 |
145144
| `gemini-3.0-pro-image-square` | 图/文生图 | 方图 |
@@ -188,8 +187,20 @@ Prometheus 可直接抓 `/metrics`。如果部署到 Kubernetes,建议只在
188187
| `veo_3_1_t2v_fast_ultra_relaxed` | 文生视频 | 横屏 |
189188
| `veo_3_1_t2v_portrait` | 文生视频 | 竖屏 |
190189
| `veo_3_1_t2v_landscape` | 文生视频 | 横屏 |
190+
| `veo_3_1_t2v_4s` | 文生视频 4秒 | 横屏 |
191+
| `veo_3_1_t2v_portrait_4s` | 文生视频 4秒 | 竖屏 |
192+
| `veo_3_1_t2v_6s` | 文生视频 6秒 | 横屏 |
193+
| `veo_3_1_t2v_portrait_6s` | 文生视频 6秒 | 竖屏 |
194+
| `veo_3_1_t2v_fast_4s` | 文生视频 Fast 4秒 | 横屏 |
195+
| `veo_3_1_t2v_fast_portrait_4s` | 文生视频 Fast 4秒 | 竖屏 |
196+
| `veo_3_1_t2v_fast_6s` | 文生视频 Fast 6秒 | 横屏 |
197+
| `veo_3_1_t2v_fast_portrait_6s` | 文生视频 Fast 6秒 | 竖屏 |
191198
| `veo_3_1_t2v_lite_portrait` | 文生视频 Lite | 竖屏 |
192199
| `veo_3_1_t2v_lite_landscape` | 文生视频 Lite | 横屏 |
200+
| `veo_3_1_t2v_lite_4s_portrait` | 文生视频 Lite 4秒 | 竖屏 |
201+
| `veo_3_1_t2v_lite_4s_landscape` | 文生视频 Lite 4秒 | 横屏 |
202+
| `veo_3_1_t2v_lite_6s_portrait` | 文生视频 Lite 6秒 | 竖屏 |
203+
| `veo_3_1_t2v_lite_6s_landscape` | 文生视频 Lite 6秒 | 横屏 |
193204

194205
#### 首尾帧模型 (I2V - Image to Video)
195206
📸 **支持1-2张图片:1张作为首帧,2张作为首尾帧**
@@ -210,10 +221,26 @@ Prometheus 可直接抓 `/metrics`。如果部署到 Kubernetes,建议只在
210221
| `veo_3_1_i2v_s_fast_ultra_relaxed` | 图生视频 | 横屏 |
211222
| `veo_3_1_i2v_s_portrait` | 图生视频 | 竖屏 |
212223
| `veo_3_1_i2v_s_landscape` | 图生视频 | 横屏 |
224+
| `veo_3_1_i2v_s_4s` | 图生视频 4秒 | 横屏 |
225+
| `veo_3_1_i2v_s_portrait_4s` | 图生视频 4秒 | 竖屏 |
226+
| `veo_3_1_i2v_s_6s` | 图生视频 6秒 | 横屏 |
227+
| `veo_3_1_i2v_s_portrait_6s` | 图生视频 6秒 | 竖屏 |
228+
| `veo_3_1_i2v_s_fast_4s_fl` | 图生视频 Fast 4秒 | 横屏 |
229+
| `veo_3_1_i2v_s_fast_portrait_4s_fl` | 图生视频 Fast 4秒 | 竖屏 |
230+
| `veo_3_1_i2v_s_fast_6s_fl` | 图生视频 Fast 6秒 | 横屏 |
231+
| `veo_3_1_i2v_s_fast_portrait_6s_fl` | 图生视频 Fast 6秒 | 竖屏 |
213232
| `veo_3_1_i2v_lite_portrait` | 图生视频 Lite(仅首帧) | 竖屏 |
214233
| `veo_3_1_i2v_lite_landscape` | 图生视频 Lite(仅首帧) | 横屏 |
234+
| `veo_3_1_i2v_lite_4s_portrait` | 图生视频 Lite 4秒(仅首帧) | 竖屏 |
235+
| `veo_3_1_i2v_lite_4s_landscape` | 图生视频 Lite 4秒(仅首帧) | 横屏 |
236+
| `veo_3_1_i2v_lite_6s_portrait` | 图生视频 Lite 6秒(仅首帧) | 竖屏 |
237+
| `veo_3_1_i2v_lite_6s_landscape` | 图生视频 Lite 6秒(仅首帧) | 横屏 |
215238
| `veo_3_1_interpolation_lite_portrait` | 图生视频 Lite(首尾帧过渡) | 竖屏 |
216239
| `veo_3_1_interpolation_lite_landscape` | 图生视频 Lite(首尾帧过渡) | 横屏 |
240+
| `veo_3_1_interpolation_lite_4s_portrait` | 图生视频 Lite 4秒(首尾帧过渡) | 竖屏 |
241+
| `veo_3_1_interpolation_lite_4s_landscape` | 图生视频 Lite 4秒(首尾帧过渡) | 横屏 |
242+
| `veo_3_1_interpolation_lite_6s_portrait` | 图生视频 Lite 6秒(首尾帧过渡) | 竖屏 |
243+
| `veo_3_1_interpolation_lite_6s_landscape` | 图生视频 Lite 6秒(首尾帧过渡) | 横屏 |
217244

218245
#### 多图生成 (R2V - Reference Images to Video)
219246
🖼️ **支持多张图片**
@@ -239,8 +266,22 @@ Prometheus 可直接抓 `/metrics`。如果部署到 Kubernetes,建议只在
239266

240267
#### 视频放大模型 (Upsample)
241268

269+
这些模型不是直接调用上游 upsampler key,而是先用对应的 Veo 3.1 普通模型生成视频,再提交 1080P/4K 放大请求。
270+
242271
| 模型名称 | 说明 | 输出 |
243272
|---------|---------|--------|
273+
| `veo_3_1_t2v_4k` | 文生视频放大 | 4K |
274+
| `veo_3_1_t2v_portrait_4k` | 文生视频放大 | 4K |
275+
| `veo_3_1_t2v_1080p` | 文生视频放大 | 1080P |
276+
| `veo_3_1_t2v_portrait_1080p` | 文生视频放大 | 1080P |
277+
| `veo_3_1_t2v_4s_4k` | 文生视频 4秒放大 | 4K |
278+
| `veo_3_1_t2v_portrait_4s_4k` | 文生视频 4秒放大 | 4K |
279+
| `veo_3_1_t2v_4s_1080p` | 文生视频 4秒放大 | 1080P |
280+
| `veo_3_1_t2v_portrait_4s_1080p` | 文生视频 4秒放大 | 1080P |
281+
| `veo_3_1_t2v_6s_4k` | 文生视频 6秒放大 | 4K |
282+
| `veo_3_1_t2v_portrait_6s_4k` | 文生视频 6秒放大 | 4K |
283+
| `veo_3_1_t2v_6s_1080p` | 文生视频 6秒放大 | 1080P |
284+
| `veo_3_1_t2v_portrait_6s_1080p` | 文生视频 6秒放大 | 1080P |
244285
| `veo_3_1_t2v_fast_portrait_4k` | 文生视频放大 | 4K |
245286
| `veo_3_1_t2v_fast_4k` | 文生视频放大 | 4K |
246287
| `veo_3_1_t2v_fast_portrait_ultra_4k` | 文生视频放大 | 4K |
@@ -253,6 +294,18 @@ Prometheus 可直接抓 `/metrics`。如果部署到 Kubernetes,建议只在
253294
| `veo_3_1_i2v_s_fast_ultra_fl_4k` | 图生视频放大 | 4K |
254295
| `veo_3_1_i2v_s_fast_portrait_ultra_fl_1080p` | 图生视频放大 | 1080P |
255296
| `veo_3_1_i2v_s_fast_ultra_fl_1080p` | 图生视频放大 | 1080P |
297+
| `veo_3_1_i2v_s_4k` | 图生视频放大 | 4K |
298+
| `veo_3_1_i2v_s_portrait_4k` | 图生视频放大 | 4K |
299+
| `veo_3_1_i2v_s_1080p` | 图生视频放大 | 1080P |
300+
| `veo_3_1_i2v_s_portrait_1080p` | 图生视频放大 | 1080P |
301+
| `veo_3_1_i2v_s_4s_4k` | 图生视频 4秒放大 | 4K |
302+
| `veo_3_1_i2v_s_portrait_4s_4k` | 图生视频 4秒放大 | 4K |
303+
| `veo_3_1_i2v_s_4s_1080p` | 图生视频 4秒放大 | 1080P |
304+
| `veo_3_1_i2v_s_portrait_4s_1080p` | 图生视频 4秒放大 | 1080P |
305+
| `veo_3_1_i2v_s_6s_4k` | 图生视频 6秒放大 | 4K |
306+
| `veo_3_1_i2v_s_portrait_6s_4k` | 图生视频 6秒放大 | 4K |
307+
| `veo_3_1_i2v_s_6s_1080p` | 图生视频 6秒放大 | 1080P |
308+
| `veo_3_1_i2v_s_portrait_6s_1080p` | 图生视频 6秒放大 | 1080P |
256309
| `veo_3_1_r2v_fast_portrait_ultra_4k` | 多图视频放大 | 4K |
257310
| `veo_3_1_r2v_fast_ultra_4k` | 多图视频放大 | 4K |
258311
| `veo_3_1_r2v_fast_portrait_ultra_1080p` | 多图视频放大 | 1080P |
@@ -486,6 +539,14 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \
486539

487540
**⭐ 如果这个项目对你有帮助,请给个 Star!**
488541

542+
## 最近更新
543+
544+
- `9f1d712` 同步 personal 打码逻辑,包含清理、浏览器参数和打码方式配置。
545+
- `da2ad06` 合并 PR #133
546+
- `abd0c00` 修复 PR #133 合并后的集成问题。
547+
- `55431c9` 将 origin/main 同步到 PR #133
548+
- `4b7a0ad` 新增 Prometheus 服务指标和 Token 健康监控。
549+
489550
## Star History
490551

491552
[![Star History Chart](https://api.star-history.com/svg?repos=TheSmallHanCat/flow2api&type=date&legend=top-left)](https://www.star-history.com/#TheSmallHanCat/flow2api&type=date&legend=top-left)

config/setting_example.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ personal_max_resident_tabs = 5 # personal 模式共享打码标签页上限,
6262
personal_idle_tab_ttl_seconds = 600 # personal 模式标签页空闲回收时间(秒)
6363
yescaptcha_api_key = "" # YesCaptcha API密钥
6464
yescaptcha_base_url = "https://api.yescaptcha.com"
65+
yescaptcha_task_type = "RecaptchaV3TaskProxylessM1" # 可选: RecaptchaV3TaskProxyless/RecaptchaV3TaskProxylessM1/RecaptchaV3TaskProxylessM1S7/RecaptchaV3TaskProxylessM1S9
6566
remote_browser_base_url = "" # 远程有头打码服务地址
6667
remote_browser_api_key = "" # 远程有头打码服务 API Key
6768
remote_browser_timeout = 60 # 远程有头打码请求超时(秒)

src/api/admin.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from curl_cffi.requests import AsyncSession
1616
from ..core.auth import AuthManager
1717
from ..core.database import Database
18-
from ..core.config import config
18+
from ..core.config import config, get_yescaptcha_min_score, normalize_yescaptcha_task_type
1919
from ..core.monitoring import build_public_health_snapshot
2020
from ..services.token_manager import TokenManager
2121
from ..services.proxy_manager import ProxyManager
@@ -339,19 +339,23 @@ async def _solve_recaptcha_with_api_service(
339339
if method == "yescaptcha":
340340
client_key = config.yescaptcha_api_key
341341
base_url = config.yescaptcha_base_url
342-
task_type = "RecaptchaV3TaskProxylessM1"
342+
task_type = config.yescaptcha_task_type
343+
min_score = get_yescaptcha_min_score(task_type)
343344
elif method == "capmonster":
344345
client_key = config.capmonster_api_key
345346
base_url = config.capmonster_base_url
346347
task_type = "RecaptchaV3TaskProxyless"
348+
min_score = None
347349
elif method == "ezcaptcha":
348350
client_key = config.ezcaptcha_api_key
349351
base_url = config.ezcaptcha_base_url
350352
task_type = "ReCaptchaV3TaskProxylessS9"
353+
min_score = None
351354
elif method == "capsolver":
352355
client_key = config.capsolver_api_key
353356
base_url = config.capsolver_base_url
354357
task_type = "ReCaptchaV3EnterpriseTaskProxyLess" if enterprise else "ReCaptchaV3TaskProxyLess"
358+
min_score = None
355359
else:
356360
raise RuntimeError(f"不支持的打码方式: {method}")
357361

@@ -364,6 +368,8 @@ async def _solve_recaptcha_with_api_service(
364368
"type": task_type,
365369
"pageAction": action,
366370
}
371+
if min_score is not None:
372+
task["minScore"] = min_score
367373

368374
if enterprise and method == "capsolver":
369375
task["isEnterprise"] = True
@@ -1575,6 +1581,7 @@ async def update_captcha_config(
15751581
captcha_method = request.get("captcha_method")
15761582
yescaptcha_api_key = request.get("yescaptcha_api_key")
15771583
yescaptcha_base_url = request.get("yescaptcha_base_url")
1584+
yescaptcha_task_type = normalize_yescaptcha_task_type(request.get("yescaptcha_task_type"))
15781585
capmonster_api_key = request.get("capmonster_api_key")
15791586
capmonster_base_url = request.get("capmonster_base_url")
15801587
ezcaptcha_api_key = request.get("ezcaptcha_api_key")
@@ -1618,6 +1625,7 @@ async def update_captcha_config(
16181625
captcha_method=captcha_method,
16191626
yescaptcha_api_key=yescaptcha_api_key,
16201627
yescaptcha_base_url=yescaptcha_base_url,
1628+
yescaptcha_task_type=yescaptcha_task_type,
16211629
capmonster_api_key=capmonster_api_key,
16221630
capmonster_base_url=capmonster_base_url,
16231631
ezcaptcha_api_key=ezcaptcha_api_key,
@@ -1667,6 +1675,7 @@ async def get_captcha_config(token: str = Depends(verify_admin_token)):
16671675
"captcha_method": captcha_config.captcha_method,
16681676
"yescaptcha_api_key": captcha_config.yescaptcha_api_key,
16691677
"yescaptcha_base_url": captcha_config.yescaptcha_base_url,
1678+
"yescaptcha_task_type": captcha_config.yescaptcha_task_type,
16701679
"capmonster_api_key": captcha_config.capmonster_api_key,
16711680
"capmonster_base_url": captcha_config.capmonster_base_url,
16721681
"ezcaptcha_api_key": captcha_config.ezcaptcha_api_key,

src/core/config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@
33
from pathlib import Path
44
from typing import Dict, Any, Optional
55

6+
DEFAULT_YESCAPTCHA_TASK_TYPE = "RecaptchaV3TaskProxylessM1"
7+
YESCAPTCHA_TASK_TYPE_OPTIONS = {
8+
"RecaptchaV3TaskProxyless": None,
9+
"RecaptchaV3TaskProxylessM1": None,
10+
"RecaptchaV3TaskProxylessM1S7": 0.7,
11+
"RecaptchaV3TaskProxylessM1S9": 0.9,
12+
}
13+
14+
15+
def normalize_yescaptcha_task_type(task_type: Optional[str]) -> str:
16+
normalized = (task_type or "").strip()
17+
if normalized in YESCAPTCHA_TASK_TYPE_OPTIONS:
18+
return normalized
19+
return DEFAULT_YESCAPTCHA_TASK_TYPE
20+
21+
22+
def get_yescaptcha_min_score(task_type: Optional[str]) -> Optional[float]:
23+
return YESCAPTCHA_TASK_TYPE_OPTIONS.get(normalize_yescaptcha_task_type(task_type))
24+
25+
626
class Config:
727
"""Application configuration"""
828

@@ -469,6 +489,22 @@ def set_yescaptcha_base_url(self, base_url: str):
469489
self._config["captcha"] = {}
470490
self._config["captcha"]["yescaptcha_base_url"] = base_url
471491

492+
@property
493+
def yescaptcha_task_type(self) -> str:
494+
"""Get YesCaptcha reCAPTCHA V3 task type"""
495+
return normalize_yescaptcha_task_type(
496+
self._config.get("captcha", {}).get(
497+
"yescaptcha_task_type",
498+
DEFAULT_YESCAPTCHA_TASK_TYPE,
499+
)
500+
)
501+
502+
def set_yescaptcha_task_type(self, task_type: str):
503+
"""Set YesCaptcha reCAPTCHA V3 task type"""
504+
if "captcha" not in self._config:
505+
self._config["captcha"] = {}
506+
self._config["captcha"]["yescaptcha_task_type"] = normalize_yescaptcha_task_type(task_type)
507+
472508
@property
473509
def capmonster_api_key(self) -> str:
474510
"""Get CapMonster API key"""

0 commit comments

Comments
 (0)