| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- """配置加载:从 .env 文件或环境变量读取,风格对齐 ContentFindAgentNew。
- 只读环境变量,不硬编码密钥。PG 是 M1 唯一必填项;其余环节配置随里程碑推进逐步使用。
- """
- from __future__ import annotations
- import os
- from dataclasses import dataclass
- from pathlib import Path
- # 我们自己的过程库 schema(与 OPEN_AIGC_PG_SCHEMA=public 区分开)
- DEFAULT_PG_SCHEMA = "creation_knowledge"
- def load_env_file(env_path: str | Path = ".env") -> dict[str, str]:
- """解析 .env 为 dict;文件不存在则返回空。与 crawapi_http._load_env_file 同款。"""
- path = Path(env_path)
- if not path.exists():
- return {}
- env: dict[str, str] = {}
- for line in path.read_text(encoding="utf-8").splitlines():
- stripped = line.strip()
- if not stripped or stripped.startswith("#") or "=" not in stripped:
- continue
- key, value = stripped.split("=", 1)
- env[key.strip()] = value.strip().strip('"').strip("'")
- return env
- def env_value(
- key: str,
- file_env: dict[str, str],
- default: str | None = None,
- required: bool = False,
- ) -> str:
- """取值优先级:os.environ > .env 文件 > default。required 缺失时报错。"""
- value = os.getenv(key) or file_env.get(key) or default
- if required and not value:
- raise RuntimeError(f"missing required env: {key}")
- return value or ""
- @dataclass
- class PgConfig:
- """过程库(Greenplum open_aigc,schema creation_knowledge)连接配置。"""
- host: str
- port: int
- user: str
- password: str
- database: str
- schema: str = DEFAULT_PG_SCHEMA
- timeout: int = 10
- @classmethod
- def from_env(cls, env_file: str | Path = ".env") -> "PgConfig":
- file_env = load_env_file(env_file)
- return cls(
- host=env_value("OPEN_AIGC_PG_HOST", file_env, required=True),
- port=int(env_value("OPEN_AIGC_PG_PORT", file_env, "5432")),
- user=env_value("OPEN_AIGC_PG_USER", file_env, required=True),
- password=env_value("OPEN_AIGC_PG_PASSWORD", file_env, required=True),
- database=env_value(
- "OPEN_AIGC_PG_DB_NAME", file_env, "open_aigc"
- ),
- schema=env_value("CK_PG_SCHEMA", file_env, DEFAULT_PG_SCHEMA),
- )
- @dataclass
- class Settings:
- """全流程配置聚合。M1 只用到 pg;其余字段供 M2+ 使用。"""
- pg: PgConfig
- # 爬虫(M2):小红书/微信等走 aiddit;抖音单独走 piaoquantv。
- aiddit_crawler_base_url: str
- crawler_timeout: int
- # OpenRouter / Gemini(遗留视频链路和兼容烟测)
- openrouter_model: str
- openrouter_timeout_seconds: float
- openrouter_base_url: str
- openrouter_api_key: str
- # 文本步 LLM(闸门/拆分/解构)
- llm_model: str
- # 卡片 / 抽帧
- max_cards: int
- frames_dir: str
- douyin_ratio: str # 视频下载偏好码率(控成本/体积),如 540p
- data_dir: str # 媒体本地落盘根目录;空字符串=关闭媒体保存(解耦开关)
- # query 搜索 + OSS 转存(默认值必填:tests/test_video_extract.py 用关键字构造 Settings 且不传这些)
- oss_upload_url: str = "http://crawler-upload-v2.aiddit.com/crawler/oss/upload_stream"
- oss_upload_timeout_seconds: int = 60
- search_default_limit: int = 5
- search_content_type: str = "图文"
- search_sort_type: str = "综合"
- # 抖音走独立后端(piaoquantv,绕开 aiddit 限流):host / account_id / cookie_batch 单独配
- piaoquantv_douyin_base_url: str = "http://crawapi.piaoquantv.com"
- piaoquantv_douyin_account_id: str = "7450041106378522636"
- piaoquantv_douyin_cookie_batch: str = "default"
- # Aliyun Bailian / Qwen(旧解构图文读懂 + 文本闸门/拆解)。
- # 带默认值,保护旧测试里直接 Settings(...) 的关键字构造。
- bailian_api_key: str = ""
- bailian_base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1"
- bailian_vl_model: str = "qwen-vl-plus"
- bailian_text_model: str = "qwen-plus"
- bailian_timeout_seconds: float = 120.0
- demo_data_dir: str = ""
- @classmethod
- def from_env(cls, env_file: str | Path = ".env") -> "Settings":
- file_env = load_env_file(env_file)
- return cls(
- pg=PgConfig.from_env(env_file),
- aiddit_crawler_base_url=env_value(
- "AIDDIT_CRAWLER_BASE_URL", file_env,
- "http://crawler.aiddit.com",
- ),
- crawler_timeout=int(env_value(
- "AIDDIT_CRAWLER_TIMEOUT_SECONDS", file_env,
- "30",
- )),
- openrouter_model=env_value(
- "OPENROUTER_MODEL", file_env,
- "google/gemini-3-flash-preview",
- ),
- openrouter_timeout_seconds=float(env_value(
- "OPENROUTER_TIMEOUT_SECONDS", file_env,
- "90",
- )),
- openrouter_base_url=env_value(
- "OPENROUTER_BASE_URL", file_env, "https://openrouter.ai/api/v1"
- ),
- openrouter_api_key=env_value("OPENROUTER_API_KEY", file_env),
- bailian_api_key=env_value("ALIYUN_BAILIAN_API_KEY", file_env),
- bailian_base_url=env_value(
- "ALIYUN_BAILIAN_BASE_URL", file_env,
- "https://dashscope.aliyuncs.com/compatible-mode/v1",
- ),
- bailian_vl_model=env_value(
- "ALIYUN_BAILIAN_VL_MODEL", file_env,
- env_value("ALIYUN_BAILIAN_MODEL", file_env, "qwen-vl-plus"),
- ),
- bailian_text_model=env_value(
- "ALIYUN_BAILIAN_TEXT_MODEL", file_env,
- env_value("ALIYUN_BAILIAN_MODEL", file_env, "qwen-plus"),
- ),
- bailian_timeout_seconds=float(env_value(
- "ALIYUN_BAILIAN_TIMEOUT_SECONDS", file_env,
- "120",
- )),
- # 文本步(筛选/拆分/解构)默认走百炼 Qwen;可用 CK_STAGE_MODEL 覆盖
- llm_model=env_value(
- "CK_STAGE_MODEL", file_env,
- env_value("ALIYUN_BAILIAN_TEXT_MODEL", file_env,
- env_value("ALIYUN_BAILIAN_MODEL", file_env, "qwen-plus")),
- ),
- max_cards=int(env_value("CK_MAX_CARDS", file_env, "12")),
- frames_dir=env_value("CK_FRAMES_DIR", file_env, "runtime/frames"),
- douyin_ratio=env_value("CK_DOUYIN_RATIO", file_env, "540p"),
- data_dir=env_value("CK_DATA_DIR", file_env, "data"),
- demo_data_dir=env_value(
- "CK_DEMO_DATA_DIR", file_env,
- str(Path(env_value("CK_DATA_DIR", file_env, "data")) / "demo"),
- ),
- oss_upload_url=env_value(
- "CRAWLER_OSS_UPLOAD_URL", file_env,
- "http://crawler-upload-v2.aiddit.com/crawler/oss/upload_stream",
- ),
- oss_upload_timeout_seconds=int(
- env_value(
- "CRAWLER_OSS_UPLOAD_TIMEOUT_SECONDS", file_env,
- "60",
- )
- ),
- search_default_limit=int(env_value(
- "CREATION_SEARCH_DEFAULT_LIMIT", file_env,
- "5",
- )),
- search_content_type=env_value(
- "CREATION_SEARCH_CONTENT_TYPE", file_env,
- "图文",
- ),
- search_sort_type=env_value(
- "CREATION_SEARCH_SORT_TYPE", file_env,
- "综合",
- ),
- piaoquantv_douyin_base_url=env_value(
- "PIAOQUANTV_DOUYIN_BASE_URL", file_env,
- "http://crawapi.piaoquantv.com",
- ),
- piaoquantv_douyin_account_id=env_value(
- "PIAOQUANTV_DOUYIN_ACCOUNT_ID", file_env,
- "7450041106378522636",
- ),
- piaoquantv_douyin_cookie_batch=env_value(
- "PIAOQUANTV_DOUYIN_COOKIE_BATCH", file_env,
- "default",
- ),
- )
- @property
- def crawler_base_url(self) -> str:
- return self.aiddit_crawler_base_url
- @property
- def douyin_base_url(self) -> str:
- return self.piaoquantv_douyin_base_url
- @property
- def douyin_account_id(self) -> str:
- return self.piaoquantv_douyin_account_id
- @property
- def douyin_cookie_batch(self) -> str:
- return self.piaoquantv_douyin_cookie_batch
- @property
- def video_model(self) -> str:
- return self.openrouter_model
|