VideoFX API客户端
| 24 | |
| 25 | |
| 26 | class FlowClient: |
| 27 | """VideoFX API客户端""" |
| 28 | |
| 29 | FLOW_PUBLIC_API_KEY = "AIzaSyBtrm0o5ab1c-Ec8ZuLcGt3oJAA5VWt3pY" |
| 30 | FLOW_BROWSER_CHANNEL_HEADER = "stable" |
| 31 | FLOW_BROWSER_COPYRIGHT_HEADER = "Copyright 2026 Google LLC. All Rights Reserved." |
| 32 | FLOW_BROWSER_VALIDATION_HEADER = "MRCPrt/rS3JY47x2Yiz9h3ag4U8=" |
| 33 | FLOW_BROWSER_YEAR_HEADER = "2026" |
| 34 | FLOW_FRONTEND_EXPERIMENT_IDS = ( |
| 35 | "106184493,106256669,105798603,106281924,106259075,106262194," |
| 36 | "105993823,106104244,105484652,1714252,105928947,106238955," |
| 37 | "106225453,106131447,1706538,119157484,106243706,105746691," |
| 38 | "106151974,106125249,106001691,106077941" |
| 39 | ) |
| 40 | YESCAPTCHA_SLOT_BACKOFF_SECONDS = (3, 5, 8, 13, 20) |
| 41 | |
| 42 | def __init__(self, proxy_manager, db=None): |
| 43 | self.proxy_manager = proxy_manager |
| 44 | self.db = db # Database instance for captcha config |
| 45 | self.labs_base_url = config.flow_labs_base_url # https://labs.google/fx/api |
| 46 | self.api_base_url = config.flow_api_base_url # https://aisandbox-pa.googleapis.com/v1 |
| 47 | self.timeout = config.flow_timeout |
| 48 | # 缓存每个账号的 User-Agent |
| 49 | self._user_agent_cache = {} |
| 50 | # 当前请求链路绑定的浏览器指纹(基于 contextvar,避免并发串扰) |
| 51 | self._request_fingerprint_ctx: contextvars.ContextVar[Optional[Dict[str, Any]]] = contextvars.ContextVar( |
| 52 | "flow_request_fingerprint", |
| 53 | default=None |
| 54 | ) |
| 55 | self._remote_browser_prefill_last_sent: Dict[str, float] = {} |
| 56 | |
| 57 | # 仅保留当前上游仍稳定出现的最小浏览器风格头;具体 UA / Accept-Language / UA-CH |
| 58 | # 统一以当前请求链路绑定的 runtime fingerprint 为准,不再兼容旧版随机平台策略。 |
| 59 | self._default_client_headers = { |
| 60 | "sec-ch-ua-mobile": "?0", |
| 61 | "sec-fetch-dest": "empty", |
| 62 | "sec-fetch-mode": "cors", |
| 63 | "sec-fetch-site": "cross-site", |
| 64 | } |
| 65 | # 发车策略改为“请求到就发”: |
| 66 | # 不在 flow2api 本地对提交做批次整形或排队,避免把同批请求打成阶梯。 |
| 67 | |
| 68 | def _generate_user_agent(self, account_id: str = None) -> str: |
| 69 | """基于账号ID生成固定的 User-Agent |
| 70 | |
| 71 | Args: |
| 72 | account_id: 账号标识(如 email 或 token_id),相同账号返回相同 UA |
| 73 | |
| 74 | Returns: |
| 75 | User-Agent 字符串 |
| 76 | """ |
| 77 | # 如果没有提供账号ID,生成随机UA |
| 78 | if not account_id: |
| 79 | account_id = f"random_{random.randint(1, 999999)}" |
| 80 | |
| 81 | # 如果已缓存,直接返回 |
| 82 | if account_id in self._user_agent_cache: |
| 83 | return self._user_agent_cache[account_id] |
no outgoing calls