文件预览

common.py

查看 bizyair-skill 技能包中的文件内容。

文件内容

scripts/common.py

"""通用常量 + 小工具集(无业务逻辑)。

这个文件存放:
  - BizyAir HTTP API 端点常量(API_BASE / CREATE_URL / WEBAPP_DETAIL_URL ...)
  - 网络/超时常量(DEFAULT_TIMEOUT / POLL_INTERVAL / MAX_POLL_SECONDS)
  - 字段识别规则集合(PROMPT_EXCLUDE_* / KNOWN_PROMPT_* / TEXT_INPUT_FIELD_TYPES)
  - 通用文本归一化与匹配评分函数(normalized_text / classify_route_match / count_term_matches ...)

被 api / contract / remote / search 等几乎所有模块依赖。修改这里要谨慎,传染面大。
"""
from __future__ import annotations
import argparse, json, re
from pathlib import Path
from paths import config_display_path as preferred_config_display_path
from typing import Any

API_BASE = 'https://api.bizyair.cn'

CREATE_URL = f'{API_BASE}/w/v1/webapp/task/openapi/create'

DETAIL_URL = f'{API_BASE}/w/v1/webapp/task/openapi/detail'

OUTPUTS_URL = f'{API_BASE}/w/v1/webapp/task/openapi/outputs'

UPLOAD_TOKEN_URL = f'{API_BASE}/x/v1/upload/token'

INPUT_COMMIT_URL = f'{API_BASE}/x/v1/input_resource/commit'

COMMUNITY_URL = f'{API_BASE}/x/v1/bizy_models/community'

OFFICIAL_URL = f'{API_BASE}/x/v1/bizy_models/official'

BIZY_MODEL_DETAIL_URL = f'{API_BASE}/x/v1/bizy_models'

RESOLVE_VERSION_URL = f'{API_BASE}/x/v1/resolve/BizyModelVersion'

SCRIPT_DIR = Path(__file__).resolve().parent

DEFAULT_TIMEOUT = 60

POLL_INTERVAL = 5

MAX_POLL_SECONDS = 900

WEBAPP_RETRY_LIMIT = 1

SEARCH_MIN_ROUNDS = 3

SEARCH_MAX_ROUNDS = 5

BIZYAIR_INFO_HOSTS = {'bizyair.cn', 'www.bizyair.cn'}

PROMPT_EXCLUDE_EN = {'title', 'caption', 'subtitle', 'watermark', 'label', 'logo'}  # 仅用于 info/prefill 展示标注

PROMPT_EXCLUDE_ZH = {'标题', '副标题', '字幕', '水印', '标签', '标语', '角标', '徽标'}  # 仅用于 info/prefill 展示标注

EXPLICIT_PROMPT_LABELS = {'prompt', 'text', '提示词', '文本', '正向提示词', '文本提示词'}  # 仅用于 info/prefill 展示标注

TEXT_INPUT_FIELD_TYPES = {'customtext', 'textarea', 'text', 'string'}

KNOWN_PROMPT_NODE_MARKERS = {'cliptextencode', 'primitivestringmultiline', 'primitivestring'}  # 仅用于 info/prefill 展示标注

KNOWN_PROMPT_FIELD_NAMES = {'prompt', 'user_prompt', 'positive_prompt'}  # 仅用于 info/prefill 展示标注

REMOTE_EXPOSED_CONTRACT_SOURCES = {'execution_target.webapp_detail.input_nodes', 'webapp_detail.input_nodes'}

REMOTE_GENERIC_PROMPT_ALIASES = {'prompt', 'text', 'value', 'positiveprompt', 'positive_prompt', 'userprompt', 'user_prompt'}

REMOTE_CONTRACT_SOURCE_PRIORITY = ['execution_target.webapp_detail.input_nodes', 'webapp_detail.input_nodes', 'workflow_hints']

def normalized_text(text: Any) -> str:
    return (str(text) if text is not None else '').strip().lower()

def config_display_path() -> str:
    return preferred_config_display_path()

def local_script_command(script_name: str, *args: str) -> str:
    script_path = (SCRIPT_DIR / script_name).resolve()
    parts = ['python3', str(script_path)]
    parts.extend((str(arg) for arg in args))
    return ' '.join(parts)

def safe_int(value: Any) -> int:
    try:
        return int(value)
    except Exception:
        return 0

def add_unique_key(items: list[str], value: str | None) -> None:
    text = str(value or '').strip()
    if text and text not in items:
        items.append(text)


WORKFLOW_LINK_NOT_SUPPORTED_MESSAGE = '你发的是 ComfyUI 的 workflow 链接(comfy-ui?id=xxx),这种链接目前不支持直接运行~\n\n如果你想执行这个工作流,可以去 BizyAir 社区找一下它对应的 AI 应用版本,把 AI 应用的链接发给我就行。\n\nAI 应用链接长这样:https://bizyair.cn/community/app/xxxxx'


def build_prompt_bundle_for_args(args: argparse.Namespace, *, route_name: str | None=None, modality: str | None=None, task: str | None=None, input_profile: dict[str, Any] | None=None) -> dict[str, Any]:
    cached = getattr(args, '_compiled_prompt_bundle', None)
    signature = (str(getattr(args, 'prompt', None) or ''), route_name, modality, task, json.dumps(input_profile or {}, ensure_ascii=False, sort_keys=True), len(getattr(args, 'image', None) or []), len(getattr(args, 'audio', None) or []))
    if isinstance(cached, dict) and cached.get('_signature') == signature:
        return cached
    raw = re.sub(r'\s+', ' ', str(getattr(args, 'prompt', None) or '').strip())
    bundle = {'raw_prompt': raw, 'card_display_prompt': raw, 'execution_prompt': raw, 'polished_prompt': raw, 'structured_prompt': raw, 'enriched_prompt': raw, 'rewritten_prompt': '', 'negative_prompt': '', 'changed': False, 'polish_notes': [], 'mode': None, 'mode_source': 'passthrough', 'style_profile': {'name': None, 'source': 'none', 'en_hint': None}, 'rewrite_applied': False}
    bundle['_signature'] = signature
    setattr(args, '_compiled_prompt_bundle', bundle)
    return bundle