diff --git a/collector-service/app/core_main.py b/collector-service/app/core_main.py index 7396628..c18e31a 100644 --- a/collector-service/app/core_main.py +++ b/collector-service/app/core_main.py @@ -167,7 +167,7 @@ class AssistantUpdateRequest(BaseModel): class GenerateCopyRequest(BaseModel): brief: str - platform: str = "抖音" + platform: str = "douyin" audience: str = "创业者" extra_requirements: str = "" knowledge_base_ids: list[str] = Field(default_factory=list) @@ -1064,6 +1064,53 @@ def fallback_transcript_from_text(title: str, content: str) -> str: return f"标题:{title}\n\n正文:\n{content.strip()}" +DOMESTIC_PLATFORMS = {"douyin", "xiaohongshu", "bilibili", "kuaishou", "wechat_video"} +PLATFORM_ALIASES = { + "抖音": "douyin", + "douyin": "douyin", + "小红书": "xiaohongshu", + "xiaohongshu": "xiaohongshu", + "哔哩哔哩": "bilibili", + "b站": "bilibili", + "bilibili": "bilibili", + "快手": "kuaishou", + "kuaishou": "kuaishou", + "微信视频号": "wechat_video", + "视频号": "wechat_video", + "wechat_video": "wechat_video", + "youtube": "youtube", +} +PLATFORM_LABELS = { + "douyin": "抖音", + "xiaohongshu": "小红书", + "bilibili": "哔哩哔哩", + "kuaishou": "快手", + "wechat_video": "微信视频号", +} + + +def normalize_platform_slug(value: str | None, *, allow_blank: bool = True) -> str: + normalized = str(value or "").strip().lower() + if not normalized: + return "" if allow_blank else "douyin" + normalized = PLATFORM_ALIASES.get(normalized, normalized) + return normalized + + +def ensure_domestic_platform(value: str | None, *, allow_blank: bool = True) -> str: + normalized = normalize_platform_slug(value, allow_blank=allow_blank) + if not normalized: + return "" + if normalized not in DOMESTIC_PLATFORMS: + raise HTTPException(status_code=400, detail=f"Unsupported platform for domestic build: {value}") + return normalized + + +def platform_label(platform: str | None) -> str: + normalized = normalize_platform_slug(platform, allow_blank=True) + return PLATFORM_LABELS.get(normalized, normalized or "抖音") + + def infer_platform_from_url(source_url: str) -> str: normalized = source_url.strip().lower() if "bilibili.com" in normalized or "b23.tv" in normalized: @@ -1080,8 +1127,6 @@ def infer_platform_from_url(source_url: str) -> str: return "kuaishou" if "channels.weixin.qq.com" in normalized or "mp.weixin.qq.com/s" in normalized: return "wechat_video" - if "youtube.com" in normalized or "youtu.be" in normalized: - return "youtube" return "" @@ -1883,6 +1928,8 @@ def dashboard(account: dict[str, Any] = Depends(require_approved)) -> dict[str, "assistants": assistants, "recent_jobs": jobs, "model_profiles": model_profiles, + "supported_platforms": sorted(DOMESTIC_PLATFORMS), + "domestic_build": True, } @@ -1916,27 +1963,35 @@ def create_project(request: ProjectCreateRequest, account: dict[str, Any] = Depe @app.get("/v2/content-sources") def list_content_sources( project_id: str | None = Query(default=None), + platform: str | None = Query(default=None), account: dict[str, Any] = Depends(require_approved), ) -> list[dict[str, Any]]: + normalized_platform = ensure_domestic_platform(platform, allow_blank=True) + clauses = ["user_id = ?"] + params: list[Any] = [account["id"]] if project_id: resolve_target_project(account["id"], project_id, username=account["username"]) - rows = db.fetch_all( - "SELECT * FROM content_sources WHERE user_id = ? AND project_id = ? ORDER BY created_at DESC", - (account["id"], project_id), - ) - else: - rows = db.fetch_all("SELECT * FROM content_sources WHERE user_id = ? ORDER BY created_at DESC", (account["id"],)) + clauses.append("project_id = ?") + params.append(project_id) + if normalized_platform: + clauses.append("platform = ?") + params.append(normalized_platform) + rows = db.fetch_all( + f"SELECT * FROM content_sources WHERE {' AND '.join(clauses)} ORDER BY created_at DESC", + tuple(params), + ) return [content_source_payload(row) for row in rows] @app.post("/v2/content-sources") def create_content_source_api(request: ContentSourceCreateRequest, account: dict[str, Any] = Depends(require_approved)) -> dict[str, Any]: project = resolve_target_project(account["id"], request.project_id or None, username=account["username"]) + normalized_platform = ensure_domestic_platform(request.platform or infer_platform_from_url(request.source_url), allow_blank=True) row = create_content_source( account_id=account["id"], project_id=project["id"], source_kind=request.source_kind.strip(), - platform=request.platform.strip(), + platform=normalized_platform, handle=request.handle.strip(), source_url=request.source_url.strip(), title=request.title.strip(), @@ -1964,7 +2019,10 @@ async def create_content_source_sync_job( source_url = (request.source_url or (source_row or {}).get("source_url") or "").strip() if not source_url: raise HTTPException(status_code=400, detail="source_url or content_source_id is required") - platform = (request.platform or (source_row or {}).get("platform") or infer_platform_from_url(source_url)).strip() + platform = ensure_domestic_platform( + request.platform or (source_row or {}).get("platform") or infer_platform_from_url(source_url), + allow_blank=False, + ) handle = (request.handle or (source_row or {}).get("handle") or "").strip() source_title = ( request.title.strip() @@ -2133,6 +2191,7 @@ def create_review(request: ReviewCreateRequest, account: dict[str, Any] = Depend if not title: title = f"{project['name']} 复盘" timestamp = utc_now() + normalized_platform = ensure_domestic_platform(request.platform, allow_blank=False) db.execute( """ INSERT INTO publish_reviews ( @@ -2148,7 +2207,7 @@ def create_review(request: ReviewCreateRequest, account: dict[str, Any] = Depend source_job["id"] if source_job else None, (assistant or {}).get("id") or None, title, - request.platform or "douyin", + normalized_platform or "douyin", request.content_type or "video", request.publish_url.strip(), request.published_at.strip(), @@ -2172,6 +2231,11 @@ def update_review(review_id: str, request: ReviewUpdateRequest, account: dict[st if request.assistant_id is not None: assistant = resolve_target_assistant(account["id"], request.assistant_id or None, current.get("project_id", "")) assistant_id = (assistant or {}).get("id") or None + normalized_platform = ( + ensure_domestic_platform(request.platform, allow_blank=False) + if request.platform is not None + else current.get("platform", "douyin") + ) db.execute( """ UPDATE publish_reviews @@ -2182,7 +2246,7 @@ def update_review(review_id: str, request: ReviewUpdateRequest, account: dict[st """, ( request.title if request.title is not None else current.get("title", ""), - request.platform if request.platform is not None else current.get("platform", "douyin"), + normalized_platform, request.content_type if request.content_type is not None else current.get("content_type", "video"), request.publish_url if request.publish_url is not None else current.get("publish_url", ""), request.published_at if request.published_at is not None else current.get("published_at", ""), @@ -2599,10 +2663,11 @@ async def generate_copy(assistant_id: str, request: GenerateCopyRequest, account prompt_excerpt = "\n\n".join(excerpts)[:6000] system_prompt = assistant.get("system_prompt") or "你是文案助手。" generation_goal = assistant.get("generation_goal") or "生成短视频文案。" + normalized_platform = ensure_domestic_platform(request.platform, allow_blank=False) user_prompt = ( f"任务目标:{generation_goal}\n" f"创作需求:{request.brief}\n" - f"平台:{request.platform}\n" + f"平台:{platform_label(normalized_platform)}\n" f"受众:{request.audience}\n" f"额外要求:{request.extra_requirements or '无'}\n\n" f"参考知识库素材:\n{prompt_excerpt or '暂无参考素材,请按通用短视频结构输出。'}\n\n"