diff --git a/.review_diffs/api.diff b/.review_diffs/api.diff new file mode 100644 index 0000000..d107e6c --- /dev/null +++ b/.review_diffs/api.diff @@ -0,0 +1,537 @@ +diff --git a/python-api/app/api/v1/caption.py b/python-api/app/api/v1/caption.py +index afae831..99a771a 100644 +--- a/python-api/app/api/v1/caption.py ++++ b/python-api/app/api/v1/caption.py +@@ -24,19 +24,6 @@ logger = logging.getLogger(__name__) + router = APIRouter(prefix="/caption", tags=["Caption"]) + + +- +- +- +- +- +- +- +- +- +- +- +- +- + @router.post("/ata/align") + async def auto_align_caption( + request_body: AutoAlignSubmitRequest, +@@ -88,9 +75,3 @@ async def auto_align_caption( + except Exception as e: + logger.error(f"自动打轴异常: {e}") + raise HTTPException(status_code=500, detail="字幕打轴失败,请稍后重试") +- +- +- +- +- +- +diff --git a/python-api/app/api/v1/points.py b/python-api/app/api/v1/points.py +index b2c7208..23bafa9 100644 +--- a/python-api/app/api/v1/points.py ++++ b/python-api/app/api/v1/points.py +@@ -6,7 +6,7 @@ + """ + + import logging +-from datetime import UTC, datetime ++from datetime import UTC, datetime, timedelta + + import httpx + from fastapi import APIRouter, Depends, HTTPException, Request +@@ -14,6 +14,7 @@ from fastapi.responses import JSONResponse + from sqlalchemy.ext.asyncio import AsyncSession + + from app.api.deps import get_current_user, get_db ++from app.core.exceptions import InsufficientPointsException + from app.crud.point_recharge_order import point_recharge_order + from app.crud.point_transaction import point_transaction + from app.models.user import User +@@ -35,6 +36,7 @@ router = APIRouter(prefix="/points", tags=["Points"]) + + # ── 余额查询 ────────────────────────────────────────── + ++ + @router.get("/balance", response_model=ApiResponse[PointBalanceResponse]) + async def get_balance( + db: AsyncSession = Depends(get_db), +@@ -47,6 +49,7 @@ async def get_balance( + + # ── 流水查询 ────────────────────────────────────────── + ++ + @router.get("/transactions", response_model=ApiResponse[PointTransactionListResponse]) + async def list_transactions( + pagination: PaginationParams = Depends(), +@@ -127,12 +130,13 @@ async def list_transactions( + + # ── 充值 ────────────────────────────────────────────── + ++ + @router.post("/recharge", response_model=ApiResponse[RechargeResponse]) + async def create_recharge_order( + request: RechargeRequest, + db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_user), +- http_request: Request = None, ++ http_request: Request = None, # type: ignore[assignment] + ): + """ + 创建积分充值订单(微信支付 Native 扫码) +@@ -303,9 +307,7 @@ async def handle_wxpay_notify( + return _wx_response() + + # 查找订单 +- order = await point_recharge_order.get_by_out_trade_no( +- db, out_trade_no=out_trade_no +- ) ++ order = await point_recharge_order.get_by_out_trade_no(db, out_trade_no=out_trade_no) + if not order: + logger.error(f"[WechatPay] 回调订单不存在: {out_trade_no}") + return _wx_response() +@@ -400,9 +402,7 @@ async def query_recharge_status( + + wxpay = get_wxpay_service() + async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client: +- wx_result = await wxpay.query_order( +- client, out_trade_no=order.out_trade_no +- ) ++ wx_result = await wxpay.query_order(client, out_trade_no=order.out_trade_no) + + order.query_result = str(wx_result) + trade_state = wx_result.get("trade_state", "") +@@ -465,6 +465,7 @@ async def query_recharge_status( + + # ── 充值档位查询 ────────────────────────────────────── + ++ + @router.get("/recharge-options", response_model=ApiResponse[list[dict]]) + async def get_recharge_options( + current_user: User = Depends(get_current_user), +@@ -480,6 +481,7 @@ async def get_recharge_options( + + # ── 扣费业务类型查询 ────────────────────────────────── + ++ + @router.get("/chargeable-types", response_model=ApiResponse[list[str]]) + async def get_chargeable_types( + current_user: User = Depends(get_current_user), +@@ -496,6 +498,7 @@ async def get_chargeable_types( + + # ── 积分规则查询 ────────────────────────────────────── + ++ + @router.get("/rules", response_model=ApiResponse[list[dict]]) + async def get_points_rules( + current_user: User = Depends(get_current_user), +@@ -530,9 +533,9 @@ async def get_points_rules( + # ── 积分预估查询 ────────────────────────────────────── + + +- + # ── 今日消费统计 ────────────────────────────────────── + ++ + @router.get("/today-consumed", response_model=ApiResponse[dict]) + async def get_today_consumed( + db: AsyncSession = Depends(get_db), +@@ -545,6 +548,7 @@ async def get_today_consumed( + + # ── 直接消费扣费(前端/Rust 层调用)─────────────────── + ++ + @router.post("/consume", response_model=ApiResponse[dict]) + async def consume_points( + request: ConsumeRequest, +@@ -569,12 +573,12 @@ async def consume_points( + source_type=request.source_type, + source_id=request.source_id, + description=f"【{request.description or request.source_type}】", +- allow_negative=False, ++ allow_negative=request.allow_negative, + ) +- except ValueError as e: ++ except InsufficientPointsException: + # 余额不足(在同一事务内判断,避免竞态) +- if "积分不足" in str(e): +- raise HTTPException(status_code=402, detail=str(e)) ++ raise ++ except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + await db.commit() + +@@ -587,5 +591,3 @@ async def consume_points( + }, + message="消费成功", + ) +- +- +diff --git a/python-api/app/api/v1/script.py b/python-api/app/api/v1/script.py +index 5e7b18f..26a11a3 100644 +--- a/python-api/app/api/v1/script.py ++++ b/python-api/app/api/v1/script.py +@@ -17,6 +17,7 @@ from sqlalchemy.ext.asyncio import AsyncSession + from app.ai.model_router import get_model_router + from app.ai.prompts import list_categories, list_prompt_files, load_prompt, render_template + from app.api.deps import get_current_user ++from app.core.exceptions import AITimeoutException, InsufficientPointsException + from app.db.session import get_db + from app.models.user import User + from app.schemas.common import ApiResponse, success_response +@@ -71,9 +72,8 @@ async def polish_content( + required_points = ps._calculate_cost("polish") + check = await ps.check_balance(db, current_user.id, required_points) + if not check["sufficient"]: +- raise HTTPException( +- status_code=402, +- detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", ++ raise InsufficientPointsException( ++ f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" + ) + + try: +@@ -99,11 +99,11 @@ async def polish_content( + data=polished, + message=f"{type_name}润色完成", + ) ++ except InsufficientPointsException: ++ raise + except HTTPException: + raise + except ValueError as e: +- if "积分不足" in str(e): +- raise HTTPException(status_code=402, detail=str(e)) + logger.warning(f"[Polish] 润色失败: {e}") + raise HTTPException(status_code=500, detail="润色失败,请检查输入内容后重试") + except Exception as e: +@@ -111,9 +111,6 @@ async def polish_content( + raise HTTPException(status_code=500, detail=f"{type_name}润色失败,请稍后重试") + + +- +- +- + @router.post("/generate-title", response_model=ApiResponse[GenerateTitleResponse]) + async def generate_title( + request: GenerateTitleRequest, +@@ -146,7 +143,11 @@ async def generate_title( + usage_note = "- 视频画面上的标题需要精炼,聚焦核心关键词\n- 副标题与主标题形成呼应,补充说明但不喧宾夺主" + + # 渲染用户提示词 +- title_type_desc = "大标题(主标题,提炼核心卖点,吸睛)" if request.title_type == "main" else "小标题(副标题,补充说明或制造悬念)" ++ title_type_desc = ( ++ "大标题(主标题,提炼核心卖点,吸睛)" ++ if request.title_type == "main" ++ else "小标题(副标题,补充说明或制造悬念)" ++ ) + user_prompt = render_template( + user_template, + title_type=request.title_type, +@@ -163,9 +164,8 @@ async def generate_title( + required_points = ps._calculate_cost("title") + check = await ps.check_balance(db, current_user.id, required_points) + if not check["sufficient"]: +- raise HTTPException( +- status_code=402, +- detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", ++ raise InsufficientPointsException( ++ f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" + ) + + try: +@@ -179,10 +179,10 @@ async def generate_title( + + title = result.content.strip() if result.content else "" + # 去除可能的引号 +- title = title.strip('"').strip("'").strip('「」').strip('『』').strip('《》') ++ title = title.strip('"').strip("'").strip("「」").strip("『』").strip("《》") + # 截断到最大长度 + if len(title) > request.max_length: +- title = title[:request.max_length] ++ title = title[: request.max_length] + + # 扣费 + points = ps._calculate_cost("title") +@@ -200,15 +200,13 @@ async def generate_title( + data=GenerateTitleResponse(title=title), + message="标题生成成功", + ) ++ except InsufficientPointsException: ++ raise + except HTTPException: + raise + except TimeoutError: + logger.warning("[generate_title] 标题生成超时") +- raise HTTPException(status_code=500, detail="标题生成超时,请重试") +- except ValueError as e: +- if "积分不足" in str(e): +- raise HTTPException(status_code=402, detail=str(e)) +- raise HTTPException(status_code=500, detail=f"标题生成失败: {str(e)}") ++ raise AITimeoutException("标题生成超时,请稍后重试") + except Exception as e: + logger.error(f"[generate_title] 标题生成失败: {e}") + raise HTTPException(status_code=500, detail=f"标题生成失败: {str(e)}") +diff --git a/python-api/app/api/v1/tasks.py b/python-api/app/api/v1/tasks.py +index ae17fe3..55965ca 100644 +--- a/python-api/app/api/v1/tasks.py ++++ b/python-api/app/api/v1/tasks.py +@@ -18,6 +18,7 @@ from fastapi import APIRouter, Depends, HTTPException + from pydantic import BaseModel, Field, field_validator + + from app.api.deps import get_current_user ++from app.core.exceptions import InsufficientPointsException + from app.core.redis_client import get_redis_client + from app.db.session import AsyncSessionLocal + from app.models.user import User +@@ -38,7 +39,6 @@ class ScriptParams(BaseModel): + category: str = Field(..., min_length=1, description="大类代码") + filename: str = Field(..., min_length=1, description="提示词文件名") + +- + @field_validator("category") + @classmethod + def validate_category(cls, v: str) -> str: +@@ -96,7 +96,9 @@ class VideoParams(BaseModel): + volume: int = Field(default=0, ge=0, le=10, description="音量") + ref_photo_url: str | None = Field(default=None, description="人脸参考图 URL") + planned_duration: float = Field(..., gt=0, description="该分镜脚本规划时长(秒),用于余额预检") +- total_planned_duration: float = Field(..., gt=0, description="所有分镜规划时长之和(秒),用于预检") ++ total_planned_duration: float = Field( ++ ..., gt=0, description="所有分镜规划时长之和(秒),用于预检" ++ ) + batch_id: str | None = Field(default=None, description="批次ID(可选)") + + @field_validator("video_url") +@@ -134,6 +136,7 @@ class TaskStatusResponse(BaseModel): + total: int = Field(0, description="总子任务数") + result: dict | None = Field(None, description="任务结果(完成时)") + error: str | None = Field(None, description="错误信息(失败时)") ++ error_code: str | None = Field(None, description="错误码(失败时,如 content_violation)") + created_at: str = Field("", description="任务创建时间(ISO格式)") + + +@@ -222,9 +225,8 @@ async def create_task( + f"[API] 积分不足: user={user_id}, type={task_type}, " + f"required={required_points}, balance={check['balance']}" + ) +- raise HTTPException( +- status_code=402, +- detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", ++ raise InsufficientPointsException( ++ f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" + ) + + # ── 3. 写入 Redis ────────────────────────────────── +@@ -246,18 +248,41 @@ async def create_task( + params=validated_params, + ) + await registry.add_running(task_id) +- +- logger.info(f"[API] Task created: {task_id}, type={task_type}, user={user_id}") +- return TaskCreateResponse( +- task_id=task_id, +- status="running", +- message=f"{task_type} 任务已创建", +- ) +- + except Exception as e: + logger.error(f"[API] Failed to update registry: {e}") + raise HTTPException(status_code=500, detail="创建任务失败:Redis写入错误") + ++ # ── 4. 脚本生成:Redis 写入成功后再扣费 ───────────── ++ if task_type == "script" and required_points > 0: ++ try: ++ async with AsyncSessionLocal() as db: ++ await ps.consume( ++ db, ++ user_id=user_id, ++ points=required_points, ++ source_type="script", ++ source_id=task_id, ++ description="【脚本生成】", ++ ) ++ await db.commit() ++ except InsufficientPointsException: ++ # 余额不足:将任务标记为失败,避免无费执行 ++ await registry.update(task_id, status="failed", message="积分不足") ++ await registry.remove_running(task_id) ++ raise ++ except Exception as e: ++ logger.error(f"[API] 脚本任务扣费失败: {e}") ++ await registry.update(task_id, status="failed", message="扣费失败") ++ await registry.remove_running(task_id) ++ raise HTTPException(status_code=500, detail="扣费失败,请稍后重试") ++ ++ logger.info(f"[API] Task created: {task_id}, type={task_type}, user={user_id}") ++ return TaskCreateResponse( ++ task_id=task_id, ++ status="running", ++ message=f"{task_type} 任务已创建", ++ ) ++ + + @router.get("", response_model=list[TaskStatusResponse]) + async def list_tasks( +@@ -294,6 +319,7 @@ async def list_tasks( + total=task.total, + result=None, # 列表查询不返回 result,避免数据过大 + error=task.error, ++ error_code=task.error_code, + created_at=task.created_at, + ) + ) +@@ -337,6 +363,7 @@ async def get_task_status( + total=task.total, + result=task.result, + error=task.error, ++ error_code=task.error_code, + created_at=task.created_at, + ) + +diff --git a/python-api/app/api/v1/vidu.py b/python-api/app/api/v1/vidu.py +index c0fb04a..401d8da 100644 +--- a/python-api/app/api/v1/vidu.py ++++ b/python-api/app/api/v1/vidu.py +@@ -44,10 +44,12 @@ async def vidu_callback(request: Request): + headers_dict = dict(request.headers) + + # 使用 APP_BASE_URL 构建 callback_url,确保与提交任务时传给 Vidu 的一致 +- #(Nginx 反向代理可能导致 request.url 的 scheme 为 http,与 Vidu 签名时的 https 不一致) ++ # (Nginx 反向代理可能导致 request.url 的 scheme 为 http,与 Vidu 签名时的 https 不一致) + app_base_url = get_settings().app_base_url + callback_url = f"{app_base_url}/api/v1/vidu/callback" if app_base_url else str(request.url) +- logger.info(f"[Vidu] 收到回调: request_url={request.url}, callback_url={callback_url}, body={body_bytes.decode('utf-8', errors='replace')[:500]}") ++ logger.info( ++ f"[Vidu] 收到回调: request_url={request.url}, callback_url={callback_url}, body={body_bytes.decode('utf-8', errors='replace')[:500]}" ++ ) + + try: + task_status = await gateway.handle_webhook( +@@ -64,15 +66,13 @@ async def vidu_callback(request: Request): + logger.error(f"[Vidu] 回调处理失败: {e}") + raise HTTPException(status_code=500, detail="回调处理失败,请稍后重试") + +- logger.info(f"[Vidu] 回调解析完成: state={task_status.state}, result={task_status.result}, error={task_status.error_message}") ++ logger.info( ++ f"[Vidu] 回调解析完成: state={task_status.state}, result={task_status.result}, error={task_status.error_message}" ++ ) + + # 2. 通过 platform_task_id 反查 Async Engine 内部 task_id,更新 TaskRegistry +- platform_task_id = ( +- task_status.result.get("task_id") if task_status.result else None +- ) +- video_url = ( +- task_status.result.get("video_url") if task_status.result else None +- ) ++ platform_task_id = task_status.result.get("task_id") if task_status.result else None ++ video_url = task_status.result.get("video_url") if task_status.result else None + + logger.info(f"[Vidu] 准备反查 internal_task_id: platform_task_id={platform_task_id}") + +@@ -121,8 +121,6 @@ async def vidu_callback(request: Request): + f"platform={platform_task_id}" + ) + else: +- logger.warning( +- f"[Vidu] 回调无法反查内部 task_id: platform={platform_task_id}" +- ) ++ logger.warning(f"[Vidu] 回调无法反查内部 task_id: platform={platform_task_id}") + + return success_response(message="回调已接收") +diff --git a/python-api/app/api/v1/voice.py b/python-api/app/api/v1/voice.py +index ba8cac9..dad2b7b 100644 +--- a/python-api/app/api/v1/voice.py ++++ b/python-api/app/api/v1/voice.py +@@ -10,12 +10,13 @@ import logging + import re + import time + import uuid ++ + from fastapi import APIRouter, Depends, HTTPException + from pydantic import BaseModel, Field + from sqlalchemy.ext.asyncio import AsyncSession + + from app.api.deps import get_current_user +-from app.core.exceptions import PlatformError ++from app.core.exceptions import InsufficientPointsException, PlatformError + from app.db.session import get_db + from app.models.user import User + from app.schemas.common import ApiResponse, success_response +@@ -49,7 +50,9 @@ class TTSSynthesizeRequest(BaseModel): + class VoiceCloneSubmitRequest(BaseModel): + """声音复刻提交请求""" + +- source_audio_url: str | None = Field(None, description="源音频 URL(5-30秒,mp3/wav,需公开可访问)") ++ source_audio_url: str | None = Field( ++ None, description="源音频 URL(5-30秒,mp3/wav,需公开可访问)" ++ ) + source_video_url: str | None = Field(None, description="源视频 URL(可选)") + video_id: str | None = Field(None, description="历史作品ID(可选)") + voice_name: str | None = Field(None, description="自定义音色名称(≤20字符)") +@@ -111,7 +114,7 @@ async def synthesize_speech( + # 宽松预检:余额为负或零时阻止,避免浪费第三方资源 + balance_info = await ps.get_user_balance(db, current_user.id) + if balance_info["balance"] <= 0: +- raise HTTPException(status_code=402, detail="余额不足,请先充值") ++ raise InsufficientPointsException("余额不足,请先充值") + + try: + audio_url = await service.synthesize( +@@ -137,10 +140,8 @@ async def synthesize_speech( + allow_negative=True, + ) + await db.commit() +- except ValueError as e: +- if "积分不足" in str(e): +- raise HTTPException(status_code=402, detail=str(e)) +- logger.error(f"[Voice] TTS 扣费失败: {e}") ++ except InsufficientPointsException: ++ raise + except Exception as e: + logger.error(f"[Voice] TTS 扣费失败: {e}") + +@@ -165,7 +166,6 @@ async def synthesize_speech( + raise HTTPException(status_code=500, detail="语音合成失败,请稍后重试") + + +- + def _normalize_voice_id(name: str | None) -> str: + """ + 将用户输入的名称规范化为 Vidu 合法的 voice_id。 +@@ -220,9 +220,8 @@ async def submit_clone_task( + required_points = ps._calculate_cost("voice_clone") + check = await ps.check_balance(db, current_user.id, required_points) + if not check["sufficient"]: +- raise HTTPException( +- status_code=402, +- detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", ++ raise InsufficientPointsException( ++ f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" + ) + + try: +@@ -244,10 +243,8 @@ async def submit_clone_task( + description="【声音复刻】", + ) + await db.commit() +- except ValueError as e: +- if "积分不足" in str(e): +- raise HTTPException(status_code=402, detail=str(e)) +- logger.error(f"[Voice] 克隆扣费失败: {e}") ++ except InsufficientPointsException: ++ raise + except Exception as e: + logger.error(f"[Voice] 克隆扣费失败: {e}") + +@@ -292,5 +289,3 @@ async def query_clone_task( + ), + message="克隆已完成", + ) +- +- diff --git a/.review_diffs/exceptions.diff b/.review_diffs/exceptions.diff new file mode 100644 index 0000000..af48ebd --- /dev/null +++ b/.review_diffs/exceptions.diff @@ -0,0 +1,146 @@ +diff --git a/python-api/app/core/exceptions.py b/python-api/app/core/exceptions.py +index d9970d5..837f8d3 100644 +--- a/python-api/app/core/exceptions.py ++++ b/python-api/app/core/exceptions.py +@@ -24,9 +24,16 @@ class AppException(HTTPException): + status_code: int, + message: str = "操作失败", + detail: dict | None = None, ++ *, ++ error_code: str | None = None, + ): +- super().__init__(status_code=status_code, detail=detail or {}) ++ body = detail or {} ++ body["message"] = message ++ if error_code: ++ body["error_code"] = error_code ++ super().__init__(status_code=status_code, detail=body) + self.message = message ++ self.error_code = error_code + + + class NotFoundException(AppException): +@@ -44,7 +51,7 @@ class ValidationException(AppException): + + def __init__(self, message: str = "参数验证失败"): + super().__init__( +- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, ++ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, + message=message, + ) + +@@ -79,6 +86,17 @@ class BusinessException(AppException): + ) + + ++class InsufficientPointsException(AppException): ++ """积分不足""" ++ ++ def __init__(self, message: str = "积分不足"): ++ super().__init__( ++ status_code=status.HTTP_402_PAYMENT_REQUIRED, ++ message=message, ++ error_code="insufficient_points", ++ ) ++ ++ + class ModelUnavailableException(AppException): + """AI 模型不可用""" + +@@ -99,6 +117,50 @@ class TaskFailedException(AppException): + ) + + ++class PromptNotFoundException(AppException): ++ """提示词文件不存在""" ++ ++ def __init__(self, message: str = "未找到提示词"): ++ super().__init__( ++ status_code=status.HTTP_404_NOT_FOUND, ++ message=message, ++ error_code="prompt_not_found", ++ ) ++ ++ ++class AIEmptyResponseException(AppException): ++ """AI 返回内容为空""" ++ ++ def __init__(self, message: str = "AI 返回内容为空"): ++ super().__init__( ++ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, ++ message=message, ++ error_code="empty_result", ++ ) ++ ++ ++class AIParseErrorException(AppException): ++ """AI 返回内容解析失败""" ++ ++ def __init__(self, message: str = "AI 返回格式解析失败"): ++ super().__init__( ++ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, ++ message=message, ++ error_code="parse_error", ++ ) ++ ++ ++class AITimeoutException(AppException): ++ """AI 调用超时""" ++ ++ def __init__(self, message: str = "AI 请求超时,请稍后重试"): ++ super().__init__( ++ status_code=status.HTTP_504_GATEWAY_TIMEOUT, ++ message=message, ++ error_code="timeout", ++ ) ++ ++ + # ═══════════════════════════════════════════════════════════════ + # 第三方平台异常(PlatformError 体系) + # ═══════════════════════════════════════════════════════════════ +@@ -111,14 +173,15 @@ class PlatformErrorType: + 确保前端和网关能够统一处理。 + """ + +- RATE_LIMIT = "rate_limit" # 429,可重试 +- AUTH_FAILED = "auth_failed" # 401/403,不可重试 +- TIMEOUT = "timeout" # 连接/读取超时,可重试 +- SERVER_ERROR = "server_error" # 第三方 5xx,可重试 +- BAD_REQUEST = "bad_request" # 参数错误,不可重试 ++ RATE_LIMIT = "rate_limit" # 429,可重试 ++ AUTH_FAILED = "auth_failed" # 401/403,不可重试 ++ TIMEOUT = "timeout" # 连接/读取超时,可重试 ++ SERVER_ERROR = "server_error" # 第三方 5xx,可重试 ++ BAD_REQUEST = "bad_request" # 参数错误,不可重试 + QUOTA_EXHAUSTED = "quota_exhausted" # 额度用完,不可重试(或延迟重试) +- NOT_FOUND = "not_found" # 资源不存在,不可重试 +- UNKNOWN = "unknown" # 兜底 ++ NOT_FOUND = "not_found" # 资源不存在,不可重试 ++ CONTENT_VIOLATION = "content_violation" # 内容安全/审核不通过,不可重试 ++ UNKNOWN = "unknown" # 兜底 + + + class PlatformError(Exception): +@@ -145,12 +208,14 @@ class PlatformError(Exception): + retryable: bool = False, + error_type: str = PlatformErrorType.UNKNOWN, + status_code: int | None = None, ++ raw_code: str | None = None, + ): + super().__init__(message) + self.platform = platform + self.retryable = retryable + self.error_type = error_type + self.status_code = status_code ++ self.raw_code = raw_code + + def to_http_status(self) -> int: + """根据 error_type 和 retryable 返回标准 HTTP 状态码""" +@@ -161,6 +226,7 @@ class PlatformError(Exception): + PlatformErrorType.AUTH_FAILED: 401, + PlatformErrorType.BAD_REQUEST: 400, + PlatformErrorType.NOT_FOUND: 404, ++ PlatformErrorType.CONTENT_VIOLATION: 400, + } + if self.error_type in mapping: + return mapping[self.error_type] diff --git a/.review_diffs/providers.diff b/.review_diffs/providers.diff new file mode 100644 index 0000000..4b56d28 --- /dev/null +++ b/.review_diffs/providers.diff @@ -0,0 +1,345 @@ +diff --git a/python-api/app/ai/providers/vidu_provider.py b/python-api/app/ai/providers/vidu_provider.py +index cab5902..fccfbbf 100644 +--- a/python-api/app/ai/providers/vidu_provider.py ++++ b/python-api/app/ai/providers/vidu_provider.py +@@ -24,8 +24,90 @@ from app.core.exceptions import PlatformError, PlatformErrorType + logger = logging.getLogger(__name__) + + +-def _map_vidu_error(status: int, message: str) -> PlatformError: +- """把 Vidu HTTP 错误映射为标准 PlatformError""" ++# Vidu 错误码分类 ++_VIDU_AUDIT_ERROR_CODES = { ++ "TaskPromptPolicyViolation", ++ "AuditSubmitIllegal", ++ "CreationPolicyViolation", ++ "PhotoAuditNotPass", ++ "AuditFailed", ++ "ImageCheckBodyJointsFailed", ++ "ImageCheckFaceFailed", ++ "ImageObjectsUndetected", ++ "FaceDetectFailure", ++ "FaceDetectNotPass", ++ "NoFaceDetected", ++ "MultiFaceDetected", ++} ++ ++_VIDU_RETRYABLE_ERROR_CODES = { ++ "InternalServiceFailure", ++ "ModelUnavailable", ++ "Unknown", ++} ++ ++_VIDU_RATE_LIMIT_ERROR_CODES = { ++ "QuotaExceeded", ++ "TooManyRequests", ++ "SystemThrottling", ++ "OperationInProcess", ++} ++ ++ ++def _extract_vidu_error_code(message: str | None) -> str | None: ++ """从 Vidu 错误信息中提取错误码""" ++ if not message: ++ return None ++ # Vidu 错误码格式:"ErrorCode: 中文描述" ++ return message.split(":")[0].strip() or None ++ ++ ++def _map_vidu_error( ++ status: int, ++ message: str, ++ *, ++ err_code: str | None = None, ++) -> PlatformError: ++ """把 Vidu HTTP 错误映射为标准 PlatformError ++ ++ 优先根据 Vidu 业务错误码(err_code)判断类型,HTTP status 仅作为兜底。 ++ """ ++ raw_code = err_code or _extract_vidu_error_code(message) ++ ++ # 1. 内容安全/审核类:不可重试 ++ if raw_code in _VIDU_AUDIT_ERROR_CODES: ++ return PlatformError( ++ message=message, ++ platform="vidu", ++ retryable=False, ++ error_type=PlatformErrorType.CONTENT_VIOLATION, ++ status_code=status, ++ raw_code=raw_code, ++ ) ++ ++ # 2. 平台内部/模型不可用:可重试 ++ if raw_code in _VIDU_RETRYABLE_ERROR_CODES: ++ return PlatformError( ++ message=message, ++ platform="vidu", ++ retryable=True, ++ error_type=PlatformErrorType.SERVER_ERROR, ++ status_code=status, ++ raw_code=raw_code, ++ ) ++ ++ # 3. 限流类:可重试 ++ if raw_code in _VIDU_RATE_LIMIT_ERROR_CODES: ++ return PlatformError( ++ message=message, ++ platform="vidu", ++ retryable=True, ++ error_type=PlatformErrorType.RATE_LIMIT, ++ status_code=status, ++ raw_code=raw_code, ++ ) ++ ++ # 4. HTTP status 兜底 + mapping = { + 429: (PlatformErrorType.RATE_LIMIT, True), + 401: (PlatformErrorType.AUTH_FAILED, False), +@@ -43,6 +125,7 @@ def _map_vidu_error(status: int, message: str) -> PlatformError: + retryable=retryable, + error_type=error_type, + status_code=status, ++ raw_code=raw_code, + ) + + +@@ -66,7 +149,9 @@ class ViduProvider: + from app.core.platform_config import get_platform_config_loader + + platform_config = get_platform_config_loader().get_platform("vidu") +- self.base_url = (platform_config.base_url if platform_config else "https://api.vidu.cn").rstrip("/") ++ self.base_url = ( ++ platform_config.base_url if platform_config else "https://api.vidu.cn" ++ ).rstrip("/") + + if not self.api_key: + raise ValueError("Vidu API Key 未配置,请在 .env 中设置 VIDU_API_KEY") +@@ -135,9 +220,12 @@ class ViduProvider: + resp = await self.client.post(url, json=body, timeout=httpx.Timeout(120.0, connect=5.0)) + data = resp.json() + if resp.status_code != 200 or data.get("state") == "failed": +- msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" +- logger.error(f"[Vidu TTS] 请求失败: url={url}, status={resp.status_code}, response={data}") +- raise _map_vidu_error(resp.status_code, f"Vidu TTS error: {msg}") ++ err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) ++ msg = err_code or data.get("message") or f"HTTP {resp.status_code}" ++ logger.error( ++ f"[Vidu TTS] 请求失败: url={url}, status={resp.status_code}, response={data}" ++ ) ++ raise _map_vidu_error(resp.status_code, f"Vidu TTS error: {msg}", err_code=err_code) + return data + except (httpx.NetworkError, httpx.TimeoutException) as e: + logger.error(f"[Vidu TTS] 网络错误: {e}") +@@ -182,9 +270,14 @@ class ViduProvider: + resp = await self.client.post(url, json=body, timeout=httpx.Timeout(120.0, connect=5.0)) + data = resp.json() + if resp.status_code != 200 or data.get("state") == "failed": +- msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" +- logger.error(f"[Vidu Clone] 请求失败: url={url}, status={resp.status_code}, response={data}") +- raise _map_vidu_error(resp.status_code, f"Vidu clone error: {msg}") ++ err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) ++ msg = err_code or data.get("message") or f"HTTP {resp.status_code}" ++ logger.error( ++ f"[Vidu Clone] 请求失败: url={url}, status={resp.status_code}, response={data}" ++ ) ++ raise _map_vidu_error( ++ resp.status_code, f"Vidu clone error: {msg}", err_code=err_code ++ ) + return data + except (httpx.NetworkError, httpx.TimeoutException) as e: + logger.error(f"[Vidu Clone] 网络错误: {e}") +@@ -238,9 +331,14 @@ class ViduProvider: + resp = await self.client.post(url, json=body) + data = resp.json() + if resp.status_code != 200 or data.get("state") == "failed": +- msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" +- logger.error(f"[Vidu LipSync] 请求失败: url={url}, status={resp.status_code}, response={data}") +- raise _map_vidu_error(resp.status_code, f"Vidu lip-sync error: {msg}") ++ err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) ++ msg = err_code or data.get("message") or f"HTTP {resp.status_code}" ++ logger.error( ++ f"[Vidu LipSync] 请求失败: url={url}, status={resp.status_code}, response={data}" ++ ) ++ raise _map_vidu_error( ++ resp.status_code, f"Vidu lip-sync error: {msg}", err_code=err_code ++ ) + return data + except (httpx.NetworkError, httpx.TimeoutException) as e: + logger.error(f"[Vidu LipSync] 网络错误: {e}") +@@ -264,9 +362,14 @@ class ViduProvider: + resp = await self.client.get(url) + data = resp.json() + if resp.status_code != 200: +- msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" +- logger.error(f"[Vidu Query] 请求失败: url={url}, status={resp.status_code}, response={data}") +- raise _map_vidu_error(resp.status_code, f"Vidu query task error: {msg}") ++ err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) ++ msg = err_code or data.get("message") or f"HTTP {resp.status_code}" ++ logger.error( ++ f"[Vidu Query] 请求失败: url={url}, status={resp.status_code}, response={data}" ++ ) ++ raise _map_vidu_error( ++ resp.status_code, f"Vidu query task error: {msg}", err_code=err_code ++ ) + return data + except (httpx.NetworkError, httpx.TimeoutException) as e: + logger.error(f"[Vidu Query] 网络错误: {e}") +diff --git a/python-api/app/ai/providers/volcengine_caption_provider.py b/python-api/app/ai/providers/volcengine_caption_provider.py +index 0f2f271..09ddcc7 100644 +--- a/python-api/app/ai/providers/volcengine_caption_provider.py ++++ b/python-api/app/ai/providers/volcengine_caption_provider.py +@@ -37,8 +37,10 @@ def _map_caption_error(status: int, message: str, code: int | None = None) -> Pl + if code is not None and code in error_mapping: + error_type, retryable = error_mapping[code] + return PlatformError( +- message, platform="volcengine_caption", +- retryable=retryable, error_type=error_type, ++ message, ++ platform="volcengine_caption", ++ retryable=retryable, ++ error_type=error_type, + status_code=status, + ) + +@@ -53,8 +55,10 @@ def _map_caption_error(status: int, message: str, code: int | None = None) -> Pl + } + error_type, retryable = http_mapping.get(status, (PlatformErrorType.UNKNOWN, False)) + return PlatformError( +- message, platform="volcengine_caption", +- retryable=retryable, error_type=error_type, ++ message, ++ platform="volcengine_caption", ++ retryable=retryable, ++ error_type=error_type, + status_code=status, + ) + +@@ -124,7 +128,7 @@ class VolcengineCaptionProvider: + max_lines: int = 1, + ) -> dict[str, Any]: + """提交字幕生成任务,返回 {id: task_id}""" +- params = { ++ params: dict[str, str | int] = { + "appid": self.appid, + "language": language, + "caption_type": caption_type, +@@ -150,11 +154,15 @@ class VolcengineCaptionProvider: + except PlatformError: + raise + except httpx.HTTPStatusError as e: +- raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e ++ raise _map_caption_error( ++ e.response.status_code, f"HTTP错误: {e.response.status_code}" ++ ) from e + except (httpx.NetworkError, httpx.TimeoutException) as e: + raise PlatformError( +- f"字幕服务网络错误: {e}", platform="volcengine_caption", +- retryable=True, error_type=PlatformErrorType.TIMEOUT, ++ f"字幕服务网络错误: {e}", ++ platform="volcengine_caption", ++ retryable=True, ++ error_type=PlatformErrorType.TIMEOUT, + ) from e + except Exception as e: + raise _map_caption_error(500, f"提交任务失败: {str(e)}") from e +@@ -165,7 +173,7 @@ class VolcengineCaptionProvider: + blocking: bool = False, + ) -> dict[str, Any]: + """查询字幕任务结果,返回原始 JSON""" +- params = { ++ params: dict[str, str | int] = { + "appid": self.appid, + "id": task_id, + "blocking": 1 if blocking else 0, +@@ -182,11 +190,15 @@ class VolcengineCaptionProvider: + except PlatformError: + raise + except httpx.HTTPStatusError as e: +- raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e ++ raise _map_caption_error( ++ e.response.status_code, f"HTTP错误: {e.response.status_code}" ++ ) from e + except (httpx.NetworkError, httpx.TimeoutException) as e: + raise PlatformError( +- f"字幕服务网络错误: {e}", platform="volcengine_caption", +- retryable=True, error_type=PlatformErrorType.TIMEOUT, ++ f"字幕服务网络错误: {e}", ++ platform="volcengine_caption", ++ retryable=True, ++ error_type=PlatformErrorType.TIMEOUT, + ) from e + except Exception as e: + raise _map_caption_error(500, f"查询任务失败: {str(e)}") from e +@@ -201,7 +213,7 @@ class VolcengineCaptionProvider: + sta_punc_mode: int = 3, + ) -> dict[str, Any]: + """提交自动字幕打轴任务,返回 {id: task_id}""" +- params = { ++ params: dict[str, str | int] = { + "appid": self.appid, + "caption_type": caption_type, + "sta_punc_mode": sta_punc_mode, +@@ -218,7 +230,9 @@ class VolcengineCaptionProvider: + response.raise_for_status() + data = response.json() + if "id" not in data: +- raise _map_caption_error(500, f"提交打轴任务失败: {data.get('message', '未知错误')}") ++ raise _map_caption_error( ++ 500, f"提交打轴任务失败: {data.get('message', '未知错误')}" ++ ) + return data + except PlatformError: + raise +diff --git a/python-api/app/ai/providers/volcengine_provider.py b/python-api/app/ai/providers/volcengine_provider.py +index 0e2a5d5..9f029a0 100644 +--- a/python-api/app/ai/providers/volcengine_provider.py ++++ b/python-api/app/ai/providers/volcengine_provider.py +@@ -291,27 +291,40 @@ class VolcengineProvider(LLMProvider): + + if status == 429 or "rate limit" in message.lower(): + return PlatformError( +- message, platform="volcengine_ark", retryable=True, +- error_type=PlatformErrorType.RATE_LIMIT, status_code=status, ++ message, ++ platform="volcengine_ark", ++ retryable=True, ++ error_type=PlatformErrorType.RATE_LIMIT, ++ status_code=status, + ) + elif status in (401, 403) or "authentication" in message.lower(): + return PlatformError( +- message, platform="volcengine_ark", retryable=False, +- error_type=PlatformErrorType.AUTH_FAILED, status_code=status, ++ message, ++ platform="volcengine_ark", ++ retryable=False, ++ error_type=PlatformErrorType.AUTH_FAILED, ++ status_code=status, + ) + elif status and status >= 500: + return PlatformError( +- message, platform="volcengine_ark", retryable=True, +- error_type=PlatformErrorType.SERVER_ERROR, status_code=status, ++ message, ++ platform="volcengine_ark", ++ retryable=True, ++ error_type=PlatformErrorType.SERVER_ERROR, ++ status_code=status, + ) + elif "timeout" in message.lower() or isinstance(e, TimeoutError): + return PlatformError( +- message, platform="volcengine_ark", retryable=True, ++ message, ++ platform="volcengine_ark", ++ retryable=True, + error_type=PlatformErrorType.TIMEOUT, + ) + else: + return PlatformError( +- message, platform="volcengine_ark", retryable=False, ++ message, ++ platform="volcengine_ark", ++ retryable=False, + error_type=PlatformErrorType.UNKNOWN, + ) + diff --git a/.review_diffs/services.diff b/.review_diffs/services.diff new file mode 100644 index 0000000..291730d --- /dev/null +++ b/.review_diffs/services.diff @@ -0,0 +1,331 @@ +diff --git a/python-api/app/services/point_service.py b/python-api/app/services/point_service.py +index 0e5d79e..709f78d 100644 +--- a/python-api/app/services/point_service.py ++++ b/python-api/app/services/point_service.py +@@ -25,7 +25,7 @@ import logging + import math + from datetime import UTC, datetime, timedelta + from pathlib import Path +-from typing import TYPE_CHECKING ++from typing import TYPE_CHECKING, Any + + import yaml + from sqlalchemy import select +@@ -33,6 +33,7 @@ from sqlalchemy.ext.asyncio import AsyncSession + + logger = logging.getLogger(__name__) + ++from app.core.exceptions import InsufficientPointsException + from app.models.point_batch import PointBatch + from app.models.point_transaction import PointTransaction + from app.models.user_point import UserPoint +@@ -46,11 +47,11 @@ if TYPE_CHECKING: + _CONFIG_PATH = Path(__file__).resolve().parents[2] / "config" / "points-config.yaml" + + +-def _load_points_config() -> dict: ++def _load_points_config() -> dict[str, Any]: + """加载积分计费配置。服务启动时读取一次,后续内存中使用。""" + if not _CONFIG_PATH.exists(): + raise FileNotFoundError(f"积分配置文件不存在: {_CONFIG_PATH}") +- with open(_CONFIG_PATH, "r", encoding="utf-8") as f: ++ with open(_CONFIG_PATH, encoding="utf-8") as f: + cfg = yaml.safe_load(f) or {} + # 合并为统一的查询字典:source_type -> {"mode": "fixed|duration|free", ...} + merged: dict[str, dict] = {} +@@ -65,18 +66,22 @@ def _load_points_config() -> dict: + return merged + + +-POINTS_CONFIG: dict[str, dict] = _load_points_config() ++POINTS_CONFIG: dict[str, Any] = _load_points_config() + + + def get_recharge_options() -> list[dict]: + """获取充值档位配置(由后端控制,支持积分赠送)""" +- return POINTS_CONFIG.get("_recharge_options", []) ++ options = POINTS_CONFIG.get("_recharge_options", []) ++ if isinstance(options, list): ++ return options ++ return [] + + + def get_chargeable_source_types() -> list[str]: + """获取所有需要扣费的业务类型列表(排除免费业务)""" + return [ +- key for key, cfg in POINTS_CONFIG.items() ++ key ++ for key, cfg in POINTS_CONFIG.items() + if not key.startswith("_") and cfg.get("mode") != "free" + ] + +@@ -163,11 +168,10 @@ def _estimate_max_cost(source_type: str, param: dict | None = None) -> int: + + # ── 余额查询 ────────────────────────────────────────── + ++ + async def get_user_balance(db: AsyncSession, user_id: UUID | str) -> dict: + """获取用户积分余额快照(实时计算,排除已过期批次)。""" +- result = await db.execute( +- select(UserPoint).where(UserPoint.user_id == user_id) +- ) ++ result = await db.execute(select(UserPoint).where(UserPoint.user_id == user_id)) + up = result.scalar_one_or_none() + + if not up: +@@ -182,8 +186,7 @@ async def get_user_balance(db: AsyncSession, user_id: UUID | str) -> dict: + from sqlalchemy import func as _func + + available_result = await db.execute( +- select(_func.coalesce(_func.sum(PointBatch.remaining), 0)) +- .where( ++ select(_func.coalesce(_func.sum(PointBatch.remaining), 0)).where( + PointBatch.user_id == user_id, + PointBatch.remaining > 0, + PointBatch.expired_at > _now(), +@@ -221,6 +224,7 @@ async def check_balance( + + # ── 充值 ────────────────────────────────────────────── + ++ + async def recharge( + db: AsyncSession, + *, +@@ -247,8 +251,7 @@ async def recharge( + # 幂等保护:同一笔订单(order_id)只能充值一次 + if order_id: + existing_result = await db.execute( +- select(PointTransaction) +- .where( ++ select(PointTransaction).where( + PointTransaction.source_id == str(order_id), + PointTransaction.type == "recharge", + ) +@@ -259,9 +262,7 @@ async def recharge( + return existing_tx + + # 1. 获取或创建用户积分账户 +- result = await db.execute( +- select(UserPoint).where(UserPoint.user_id == user_id) +- ) ++ result = await db.execute(select(UserPoint).where(UserPoint.user_id == user_id)) + up = result.scalar_one_or_none() + + if not up: +@@ -353,7 +354,7 @@ async def consume( + 直接扣费(后置计费)。 + + 业务执行成功后调用,按实际消耗直接扣除余额。 +- 默认不允许欠费(余额不足时抛出 ValueError)。 ++ 默认不允许欠费(余额不足时抛出 InsufficientPointsException)。 + Scheduler 后置扣费等场景可设置 allow_negative=True,允许余额变负。 + + :param points: 实际消耗积分(正整数) +@@ -383,9 +384,7 @@ async def consume( + + # 2. 获取用户积分账户(加锁) + result = await db.execute( +- select(UserPoint) +- .where(UserPoint.user_id == user_id) +- .with_for_update() ++ select(UserPoint).where(UserPoint.user_id == user_id).with_for_update() + ) + up = result.scalar_one_or_none() + +@@ -404,7 +403,7 @@ async def consume( + # 3. 余额检查:用实时可用余额(未过期批次 remaining 总和),避免 expire_batches 延迟导致超扣 + available = sum(b.remaining for b in batches) + if not allow_negative and available < points: +- raise ValueError(f"积分不足,当前可用余额 {available},需要 {points} 积分") ++ raise InsufficientPointsException(f"积分不足,当前可用余额 {available},需要 {points} 积分") + + remaining_to_deduct = points + for batch in batches: +@@ -440,6 +439,7 @@ async def consume( + + # ── 过期回收 ────────────────────────────────────────── + ++ + async def expire_batches(db: AsyncSession) -> int: + """ + 回收过期积分批次。返回过期积分总数。 +@@ -468,9 +468,7 @@ async def expire_batches(db: AsyncSession) -> int: + + # 获取用户积分账户(加锁) + up_result = await db.execute( +- select(UserPoint) +- .where(UserPoint.user_id == batch.user_id) +- .with_for_update() ++ select(UserPoint).where(UserPoint.user_id == batch.user_id).with_for_update() + ) + up = up_result.scalar_one_or_none() + if not up: +diff --git a/python-api/app/services/script_service.py b/python-api/app/services/script_service.py +index 49aa4b1..60f58d5 100644 +--- a/python-api/app/services/script_service.py ++++ b/python-api/app/services/script_service.py +@@ -7,9 +7,16 @@ import asyncio + import logging + import time + from pathlib import Path ++from typing import Any + + from app.ai.model_router import get_model_router + from app.ai.prompts import load_prompt_file, load_script_user_prompt ++from app.core.exceptions import ( ++ AIEmptyResponseException, ++ AIParseErrorException, ++ AITimeoutException, ++ PromptNotFoundException, ++) + from app.schemas.script import ScriptShot + from app.services.ai_response_utils import ( + safe_parse_ai_json_response, +@@ -22,12 +29,9 @@ logger = logging.getLogger(__name__) + class ScriptService: + """脚本生成服务""" + +- + def __init__(self): + self.prompts_dir = Path(__file__).parent.parent / "ai" / "prompts" + +- +- + def _load_prompt(self, name: str) -> str: + """加载 Prompt 模板""" + prompt_file = self.prompts_dir / f"{name}.txt" +@@ -58,7 +62,7 @@ class ScriptService: + # 加载 Prompt + system_prompt = load_prompt_file(category, filename) + if not system_prompt: +- raise ValueError(f"未找到提示词: category={category}, filename={filename}") ++ raise PromptNotFoundException(f"未找到提示词: category={category}, filename={filename}") + + # 用户提示词 + user_prompt = load_script_user_prompt( +@@ -75,24 +79,26 @@ class ScriptService: + ) + + if not result.content or not result.content.strip(): +- raise ValueError("AI 返回内容为空,请检查模型配置或重试") ++ raise AIEmptyResponseException("AI 返回内容为空,请检查模型配置或重试") + + success, parsed_data, error_msg = safe_parse_ai_json_response(result.content) + + if not success: +- raise ValueError(error_msg or "AI 返回格式错误,无法解析为 JSON") ++ raise AIParseErrorException(error_msg or "AI 返回格式错误,无法解析为 JSON") + + try: + shots_data = validate_and_normalize_shots(parsed_data) + + if not shots_data: +- raise ValueError("AI 返回的分镜数据为空或格式不正确") ++ raise AIEmptyResponseException("AI 返回的分镜数据为空或格式不正确") + + shots = [ScriptShot(**shot) for shot in shots_data] + return shots + ++ except (AIEmptyResponseException, AIParseErrorException): ++ raise + except Exception as e: +- raise ValueError(f"分镜数据处理失败: {str(e)}") ++ raise AIParseErrorException(f"分镜数据处理失败: {str(e)}") + + async def polish_content( + self, +@@ -144,21 +150,23 @@ class ScriptService: + ) + return result.content.strip() + except TimeoutError: +- raise ValueError("润色请求超时,请重试") ++ raise AITimeoutException("润色请求超时,请重试") ++ except (AIEmptyResponseException, AIParseErrorException, AITimeoutException): ++ raise + except Exception as e: +- raise ValueError(f"润色失败: {str(e)}") ++ raise AIParseErrorException(f"润色失败: {str(e)}") + + async def check_model_health(self) -> dict: + """检查模型健康状态""" + model_router = await get_model_router() + health_results = await model_router.health_check() + +- models = [] ++ models: list[dict[str, Any]] = [] + available_count = 0 +- recommended = None ++ recommended: dict[str, Any] | None = None + + for _provider_id, health in health_results.items(): +- model_info = { ++ model_info: dict[str, Any] = { + "id": health.id, + "name": health.name, + "is_available": health.is_available, +@@ -169,9 +177,12 @@ class ScriptService: + + if health.is_available: + available_count += 1 +- if recommended is None or health.response_time < recommended.get( +- "response_time", float("inf") +- ): ++ current_best = ( ++ float("inf") ++ if recommended is None ++ else float(recommended.get("response_time") or float("inf")) ++ ) ++ if health.response_time < current_best: + recommended = model_info + + total = len(models) +@@ -188,7 +199,6 @@ class ScriptService: + """测试指定模型连接""" + model_router = await get_model_router() + +- + start_time = time.time() + + try: +diff --git a/python-api/app/services/vidu_service.py b/python-api/app/services/vidu_service.py +index 054823f..61bbdcd 100644 +--- a/python-api/app/services/vidu_service.py ++++ b/python-api/app/services/vidu_service.py +@@ -207,8 +207,9 @@ class ViduService: + error_type=PlatformErrorType.BAD_REQUEST, + ) + +- logger.info(f"[Vidu Clone] 复刻成功: voice_id={result.data.get('voice_id')}") +- return result.data or {} ++ clone_data = result.data or {} ++ logger.info(f"[Vidu Clone] 复刻成功: voice_id={clone_data.get('voice_id')}") ++ return clone_data + + async def query_clone_task(self, voice_id: str) -> dict[str, Any]: + """Vidu 声音复刻是同步接口,无独立查询。 +@@ -270,6 +271,8 @@ class ViduService: + result_data = status.result or {} + return { + "state": ViduAdapter.denormalize_state(status.state), +- "creations": [{"url": result_data.get("video_url")}] if result_data.get("video_url") else [], ++ "creations": ( ++ [{"url": result_data.get("video_url")}] if result_data.get("video_url") else [] ++ ), + "message": status.error_message, + } +diff --git a/python-api/app/services/volcengine_caption_service.py b/python-api/app/services/volcengine_caption_service.py +index 83f59b4..9a565a5 100644 +--- a/python-api/app/services/volcengine_caption_service.py ++++ b/python-api/app/services/volcengine_caption_service.py +@@ -155,10 +155,7 @@ class VolcengineCaptionService: + error_type=PlatformErrorType.BAD_REQUEST, + ) + +- logger.warning( +- f"{task_name}超过最大轮询次数: task_id={task_id}, " +- f"retries={retries}" +- ) ++ logger.warning(f"{task_name}超过最大轮询次数: task_id={task_id}, " f"retries={retries}") + raise PlatformError( + f"{task_name}超时,请稍后重试", + platform="volcengine_caption", diff --git a/AGENTS.md b/AGENTS.md index 1ab32a1..b5d8ea1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ **美家卡智影**是一款面向桌面端的 AI 视频创作应用,采用"Python 后端 API + Tauri 桌面前端"的混合架构。 - **产品标识**: `cn.meijiaka.ai-video` / `cn.meijiaka.ai-zy` -- **版本**: `1.8.2` +- **版本**: `1.9.1` - **核心功能**: AI 脚本生成、AI 配音合成(TTS)、声音复刻、视频生成(Vidu)、视频字幕生成、压制成片(FFmpeg)、项目本地持久化 ### 技术栈总览 @@ -25,7 +25,7 @@ | 前端构建 | Vite 7 | | 状态管理 | Zustand 5 + Immer 11 | | 路由 | `react-router-dom` | -| 数据请求 | 自研智能路由客户端 + SWR | +| 数据请求 | HTTP 客户端 (`src/api/client.ts`) + SWR | | 测试(后端) | pytest + pytest-asyncio | | 测试(前端) | Vitest 4 + jsdom + `@testing-library/react` | | 部署 | Docker + Docker Compose + Nginx | @@ -42,7 +42,7 @@ ├── tauri-app/ # Tauri 桌面前端 ├── docs/ # 项目文档(架构设计、API 对接指南等) ├── scripts/ # 辅助脚本 -├── .gitlab-ci.yml # GitLab CI/CD 配置 +├── .github/workflows/ # GitHub Actions CI/CD 配置 └── AGENTS.md # 本文档 ``` @@ -51,7 +51,7 @@ ``` python-api/ ├── app/ # 主应用代码 -│ ├── api/v1/ # API 路由(按领域拆分:auth, script, voice, vidu, caption, tasks, upload, materials, system) +│ ├── api/v1/ # API 路由(按领域拆分:auth, script, voice, vidu, caption, tasks, upload, materials, system, bgm_music, cover_background, image, points, update, events) │ ├── core/ # 核心工具(配置加载、安全、异常、Redis 客户端、健康检查) │ ├── db/ # 数据库配置与会话管理 │ ├── models/ # SQLAlchemy ORM 模型(BaseModel 提供 UUID 主键 + 时间戳) @@ -62,7 +62,7 @@ python-api/ │ ├── crud/ # 数据库 CRUD 封装 │ ├── config.py # Pydantic Settings 配置管理 │ └── main.py # FastAPI 应用入口(含 lifespan 管理) -├── config/ # 运行时配置文件(platform-config.yaml, materials.json) +├── config/ # 运行时配置文件(platform-config.yaml, points-config.yaml) ├── alembic/ # 数据库迁移脚本 ├── nginx/ # Nginx 反向代理配置(含 acme.sh SSL 证书脚本) ├── Dockerfile # 多阶段构建镜像(builder + production) @@ -81,12 +81,11 @@ python-api/ tauri-app/ ├── src/ # React 前端源码 │ ├── api/ # API 客户端与模块 -│ │ ├── client.ts # 智能路由客户端(HTTP / IPC 自动选择,camelCase ↔ snake_case 自动转换) -│ │ ├── generated/ # OpenAPI 生成的 TypeScript 类型 +│ │ ├── client.ts # HTTP 客户端(camelCase ↔ snake_case 自动转换) │ │ └── modules/ # 按领域拆分的 API 模块 │ ├── components/ # 可复用组件(PascalCase 文件夹) │ ├── pages/ # 页面级组件(PascalCase 文件夹) -│ ├── store/ # Zustand 状态管理(含 __tests__) +│ ├── store/ # Zustand 状态管理 │ ├── hooks/ # 自定义 React Hooks │ ├── utils/ # 工具函数 │ ├── styles/ # CSS 变量与全局样式 @@ -97,11 +96,8 @@ tauri-app/ │ │ ├── lib.rs # Tauri Builder、Command 定义、公共类型 │ │ ├── ffmpeg_cmd.rs # FFmpeg 命令封装 │ │ ├── video_processing.rs # 压制成片业务逻辑 -│ │ ├── api_proxy.rs # Python API 代理 -│ │ ├── auth.rs # 认证命令 -│ │ ├── avatar_cache.rs # 头像缓存 │ │ ├── storage/ # 本地存储引擎(项目、认证、配置、头像等) -│ │ ├── commands/ # Tauri IPC 命令(按领域拆分) +│ │ ├── commands/ # Tauri IPC 命令(按领域拆分:asset, auth_state, cover_avatar, file, product, project, video_compose, voice 等) │ │ └── utils.rs # 通用工具 │ ├── Cargo.toml # Rust 依赖 │ ├── tauri.conf.json # Tauri 应用配置(窗口、CSP、打包、sidecar) @@ -231,8 +227,7 @@ npm run format:check # Prettier --check npm run stylelint # Stylelint npm run stylelint:fix # Stylelint --fix -# OpenAPI 类型生成 -npm run gen:api # 根据 openapi.json 生成 TypeScript 类型 +# 注:当前项目未配置 OpenAPI 自动生成 TypeScript 类型的脚本 ``` --- @@ -280,7 +275,7 @@ npm run gen:api # 根据 openapi.json 生成 TypeScript 类型 1. **判断是否需要本地能力**(FFmpeg、文件系统、系统调用)。 2. **不需要** → 直接在 `tauri-app/src/api/modules/` 使用 `client.get/post/put/delete` 调用 Python HTTP API。 -3. **需要** → 将 endpoint 加入 `tauri-app/src/api/client.ts` 的 IPC 处理逻辑,并在 `tauri-app/src-tauri/src/commands/` 或 `lib.rs` 中实现对应的 `#[tauri::command]` 处理器。 +3. **需要** → 在 `tauri-app/src/api/modules/` 中通过 `@tauri-apps/api/core` 的 `invoke` 调用 Rust 命令,并在 `tauri-app/src-tauri/src/commands/` 或 `lib.rs` 中实现对应的 `#[tauri::command]` 处理器。 ### 语义层防护网(后端) @@ -304,7 +299,6 @@ Makefile 中 `lint-semantic` 目标会检查以下规则: - **组件测试**: `@testing-library/react` + `@testing-library/jest-dom` - **文件位置**: - 全局 setup: `src/__tests__/setup.ts` - - Store 测试: `src/store/__tests__/*.test.tsx` - 组件/页面测试: 建议放在被测文件同目录或 `__tests__` 子目录中 - **Mock 策略**: `setup.ts` 中已全局 mock `localStorage`、`@tauri-apps/api/core` 的 `invoke` 方法、`window.__TAURI_INTERNALS__`。每个测试后自动调用 `vi.clearAllMocks()`。 @@ -327,13 +321,11 @@ Makefile 中 `lint-semantic` 目标会检查以下规则: ### 部署流程 -#### 测试环境(GitLab CI) +#### 测试环境(GitHub Actions) -`.gitlab-ci.yml` 定义了 `deploy-backend` 任务: -1. 在部署服务器拉取代码(`master` 分支触发)。 -2. 构建 api + scheduler 镜像(`docker-compose.test.yml`)。 -3. 启动服务,健康检查 `curl http://localhost:8081/health`。 -4. 清理 7 天前的旧镜像。 +`.github/workflows/` 存放 CI/CD 工作流: +- `release.yml`:Tauri 桌面端 Release 打包工作流(按 tag 触发,支持 macOS / Windows 平台及 sidecar 二进制下载)。 +- 后端 api + scheduler 的测试/生产部署目前通过手动执行 `docker-compose.test.yml` / `docker-compose.prod.yml` 完成。 #### 生产环境 @@ -384,7 +376,7 @@ Makefile 中 `lint-semantic` 目标会检查以下规则: - **ORM**: SQLAlchemy 2.0(异步,asyncpg 驱动) - **迁移工具**: Alembic - **基础模型**: `app.models.base.BaseModel` 提供 UUID 主键、`created_at`、`updated_at` -- **当前模型**: `User`(用户/设备认证) +- **当前模型**: 包括 `User`(用户/设备认证)、`UserDevice`、`UserPoint`、`PointRechargeOrder`、`PointTransaction`、`BrollCategory`、`BrollMaterial`、`BrollTag`、`CoverBackground`、`BgmMusic`、`Update` 等 - **迁移注意**: Alembic 使用同步连接(psycopg2),会自动将 `+asyncpg` 替换掉。 --- diff --git a/VERSION b/VERSION index a7ee35a..ee672d8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.3 +1.9.1 \ No newline at end of file diff --git a/python-api/Makefile b/python-api/Makefile index 59d1bb9..4b85e7f 100644 --- a/python-api/Makefile +++ b/python-api/Makefile @@ -115,26 +115,20 @@ lint-semantic: ## 语义层禁词检查(防止供应商术语泄漏到业务 echo "❌ API 层发现 element_id(应使用 provider_element_id 或 human_id)"; \ exit 1; \ fi - @# Scheduler 层禁止 task_id 作为内部变量/Redis key(读取 Provider 返回除外) - @errs=$$(grep -rn '\btask_id\b' app/scheduler --include='*.py' \ - | grep -v 'job_id' \ - | grep -v '__pycache__' \ - | grep -v '\.get("task_id")' \ - | grep -v 'result.get("task_id")' \ - | grep -v 'task_type' \ - | grep -v '"task_id"' \ - | grep -v "'task_id'"); \ - if [ -n "$$errs" ]; then \ - echo "$$errs"; \ - echo "❌ Scheduler 层发现 task_id(应使用 job_id)"; \ - exit 1; \ - fi - @# Scheduler 层 Redis key 必须使用 job: 而非 task: - @errs=$$(grep -rn 'redis.*task:' app/scheduler --include='*.py' \ + @# Scheduler 层统一使用 task 命名,禁止混用 job + @errs=$$(grep -rn '\bjob_id\b' app/scheduler --include='*.py' \ | grep -v '__pycache__'); \ if [ -n "$$errs" ]; then \ echo "$$errs"; \ - echo "❌ Scheduler Redis key 使用 task:(应使用 job:)"; \ + echo "❌ Scheduler 层发现 job_id(应使用 task_id)"; \ + exit 1; \ + fi + @# Scheduler 层 Redis key 必须使用 task: 而非 job: + @errs=$$(grep -rn 'redis.*job:' app/scheduler --include='*.py' \ + | grep -v '__pycache__'); \ + if [ -n "$$errs" ]; then \ + echo "$$errs"; \ + echo "❌ Scheduler Redis key 使用 job:(应使用 task:)"; \ exit 1; \ fi @echo "✅ 语义层检查通过" diff --git a/python-api/app/ai/adapters/vidu_adapter.py b/python-api/app/ai/adapters/vidu_adapter.py index 43ea3b1..2595671 100644 --- a/python-api/app/ai/adapters/vidu_adapter.py +++ b/python-api/app/ai/adapters/vidu_adapter.py @@ -113,7 +113,7 @@ class ViduAdapter(PlatformAdapter, SyncCapable, TaskCapable, CallbackCapable): result = await self.provider.clone_voice( audio_url=payload["audio_url"], voice_id=payload["voice_id"], - text=payload.get("text"), + text=payload.get("text") or "", ) return AdapterResponse( success=True, @@ -219,6 +219,7 @@ class ViduAdapter(PlatformAdapter, SyncCapable, TaskCapable, CallbackCapable): ) -> bool: """验证 Vidu 回调 HMAC-SHA256 签名""" import logging + logger = logging.getLogger(__name__) # HTTP 头大小写不敏感:建立小写 key 的查找表 @@ -233,6 +234,9 @@ class ViduAdapter(PlatformAdapter, SyncCapable, TaskCapable, CallbackCapable): if not all([signature, algorithm, access_key, signed_headers_str, date]): logger.warning(f"[Vidu] 签名验证失败: 缺少必要头, headers={list(headers.keys())}") return False + assert signature is not None + assert signed_headers_str is not None + assert date is not None if algorithm != "hmac-sha256": logger.warning(f"[Vidu] 签名验证失败: 不支持的算法 {algorithm}") return False @@ -256,17 +260,15 @@ class ViduAdapter(PlatformAdapter, SyncCapable, TaskCapable, CallbackCapable): canonical_query_string = parsed.query or "" signing_string = ( - f"POST\n" - f"{http_uri}\n" - f"{canonical_query_string}\n" - f"vidu\n" - f"{date}\n" + f"POST\n" f"{http_uri}\n" f"{canonical_query_string}\n" f"vidu\n" f"{date}\n" ) for name in header_names: signing_string += f"{name}:{header_values[name]}\n" expected = base64.b64encode( - hmac.new(secret.encode("utf-8"), signing_string.encode("utf-8"), hashlib.sha256).digest() + hmac.new( + secret.encode("utf-8"), signing_string.encode("utf-8"), hashlib.sha256 + ).digest() ).decode("utf-8") if not hmac.compare_digest(signature, expected): @@ -307,6 +309,12 @@ class ViduAdapter(PlatformAdapter, SyncCapable, TaskCapable, CallbackCapable): return TaskStatus( state=self.normalize_state(state), - result={"video_url": video_url, "creations": creations, "task_id": task_id} if video_url else {"task_id": task_id}, - error_message=(data.get("err_code") or data.get("message")) if state == "failed" else None, + result=( + {"video_url": video_url, "creations": creations, "task_id": task_id} + if video_url + else {"task_id": task_id} + ), + error_message=( + (data.get("err_code") or data.get("message")) if state == "failed" else None + ), ) diff --git a/python-api/app/ai/adapters/volcengine_ark_adapter.py b/python-api/app/ai/adapters/volcengine_ark_adapter.py index 645ecde..7ac4a6f 100644 --- a/python-api/app/ai/adapters/volcengine_ark_adapter.py +++ b/python-api/app/ai/adapters/volcengine_ark_adapter.py @@ -69,11 +69,11 @@ class VolcengineArkAdapter(PlatformAdapter, SyncCapable): ) elif method == Method.EMBEDDING: - result = await self.provider.create_embeddings( + embedding_result: dict[str, Any] = await self.provider.create_embeddings( texts=payload["texts"], model=payload.get("model"), ) - return AdapterResponse(success=True, data=result) + return AdapterResponse(success=True, data=embedding_result) else: return AdapterResponse( diff --git a/python-api/app/ai/gateways/llm_gateway.py b/python-api/app/ai/gateways/llm_gateway.py index 147f0fd..74c1231 100644 --- a/python-api/app/ai/gateways/llm_gateway.py +++ b/python-api/app/ai/gateways/llm_gateway.py @@ -24,7 +24,9 @@ logger = logging.getLogger(__name__) class LLMGateway: """LLM 调用网关""" - def __init__(self, adapters: dict[str, SyncCapable], fallback_chains: dict[str, list[str]] | None = None): + def __init__( + self, adapters: dict[str, SyncCapable], fallback_chains: dict[str, list[str]] | None = None + ): self.adapters = adapters self.fallback_chains = fallback_chains or {} @@ -55,15 +57,18 @@ class LLMGateway: for mid in models_to_try: adapter = self._get_adapter(platform) try: - result = await adapter.call(Method.CHAT, { - "prompt": prompt, - "model": mid, - **kwargs, - }) + result = await adapter.call( + Method.CHAT, + { + "prompt": prompt, + "model": mid, + **kwargs, + }, + ) if result.success: if mid != model_id: logger.warning(f"[LLMGateway] 模型降级成功: {model_id} → {mid}") - return result.data + return result.data or {} else: last_error = PlatformError( result.error_message or f"模型 {mid} 调用失败", @@ -82,6 +87,3 @@ class LLMGateway: platform=platform, retryable=False, ) - - - diff --git a/python-api/app/ai/model_router.py b/python-api/app/ai/model_router.py index 756425e..ebfc4c0 100644 --- a/python-api/app/ai/model_router.py +++ b/python-api/app/ai/model_router.py @@ -13,6 +13,7 @@ from app.ai.adapters.constants import Method from app.ai.providers.base import GenerationResult, ModelHealth, ProviderError from app.ai.providers.volcengine_provider import VolcengineProvider from app.core.config_loader import AIModelConfigLoader, get_config_loader +from app.core.exceptions import AppException, PlatformError from app.platform_gateway import PlatformGateway logger = logging.getLogger(__name__) @@ -26,9 +27,7 @@ class _PlatformInstance: self.gateway = gateway self.provider_id = config.get("id", "") - async def generate( - self, model_name: str, prompt: str, **kwargs - ) -> GenerationResult: + async def generate(self, model_name: str, prompt: str, **kwargs) -> GenerationResult: """调用生成(通过 PlatformGateway)""" if self.gateway: result = await self.gateway.call_sync( @@ -41,9 +40,7 @@ class _PlatformInstance: }, ) if not result.success: - raise ProviderError( - result.error_message or f"{self.provider_id} 调用失败" - ) + raise ProviderError(result.error_message or f"{self.provider_id} 调用失败") data = result.data or {} return GenerationResult( content=data.get("content", ""), @@ -64,7 +61,11 @@ class _PlatformInstance: id=model_name or self.provider_id, name=self.provider_id, is_available=adapter_result.success, - response_time=adapter_result.data.get("response_time_ms", 0) if adapter_result.data else 0, + response_time=( + adapter_result.data.get("response_time_ms", 0) + if adapter_result.data + else 0 + ), last_error=adapter_result.error_message, ) except Exception as e: @@ -89,7 +90,6 @@ class ModelRouter: - 模型自动选择 """ - def __init__(self): self.platforms: dict[str, _PlatformInstance] = {} self._config_loader: AIModelConfigLoader | None = None @@ -249,11 +249,7 @@ class ModelRouter: if task_type: model_id = self.select_model_for_task(task_type) if model_id is None: - models = ( - self._config_loader.get_enabled_models() - if self._config_loader - else [] - ) + models = self._config_loader.get_enabled_models() if self._config_loader else [] if models: model_id = models[0].id else: @@ -270,9 +266,9 @@ class ModelRouter: params = {**model.default_params, **kwargs} try: - return await platform.generate( - prompt=prompt, model_name=model.model_name, **params - ) + return await platform.generate(prompt=prompt, model_name=model.model_name, **params) + except (PlatformError, AppException): + raise except Exception as e: raise ProviderError(f"模型 {model_id} 生成失败: {e}") from e @@ -290,7 +286,11 @@ class ModelRouter: id=model.id, name=model.display_name, is_available=adapter_result.success, - response_time=adapter_result.data.get("response_time_ms", 0) if adapter_result.data else 0, + response_time=( + adapter_result.data.get("response_time_ms", 0) + if adapter_result.data + else 0 + ), last_error=adapter_result.error_message, ) else: @@ -306,11 +306,12 @@ class ModelRouter: # fallback: 直接通过 PlatformInstance results = {} if model_id: - model = self._config_loader.get_model(model_id) if self._config_loader else None - if model: - platform = self.platforms.get(model.platform_id) - if platform: - results[model_id] = await platform.health_check(model.model_name) + target_model = self._config_loader.get_model(model_id) if self._config_loader else None + if target_model is None: + raise ProviderError(f"模型不存在: {model_id}") + platform = self.platforms.get(target_model.platform_id) + if platform: + results[model_id] = await platform.health_check(target_model.model_name) else: if self._config_loader: for model in self._config_loader.get_enabled_models(): diff --git a/python-api/app/ai/prompts/loader.py b/python-api/app/ai/prompts/loader.py index ab61191..143a274 100644 --- a/python-api/app/ai/prompts/loader.py +++ b/python-api/app/ai/prompts/loader.py @@ -94,10 +94,12 @@ def list_categories() -> list[dict]: for cat_meta in meta.get("categories", []): cat_code = cat_meta["code"] cat_name = cat_meta.get("name", cat_code) - categories.append({ - "code": cat_code, - "name": cat_name, - }) + categories.append( + { + "code": cat_code, + "name": cat_name, + } + ) return categories @@ -135,11 +137,13 @@ def list_prompt_files(category: str) -> list[dict]: else: label = name desc = "" - files.append({ - "filename": f.name, - "label": label.strip(), - "desc": desc.strip(), - }) + files.append( + { + "filename": f.name, + "label": label.strip(), + "desc": desc.strip(), + } + ) return files @@ -174,7 +178,6 @@ def load_system_prompt(category: str, subcategory: str) -> str: return load_prompt_file(category, chosen["filename"]) - def load_script_user_prompt( topic: str, extra_params: str | None = None, diff --git a/python-api/app/ai/prompts/system/bk/停工关键节点——装修必须停工的7个时间点.txt b/python-api/app/ai/prompts/system/bk/停工关键节点——装修必须停工的7个时间点.txt index 68a11c8..383edbd 100644 --- a/python-api/app/ai/prompts/system/bk/停工关键节点——装修必须停工的7个时间点.txt +++ b/python-api/app/ai/prompts/system/bk/停工关键节点——装修必须停工的7个时间点.txt @@ -1,99 +1,99 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -你的任务是生成装修避坑口播文案,必须严格遵守以下所有规则,不得有任何偏差: - -1. 固定开头:第一行意思【装修这几个时间点必须停工】,文案可微调句式口语化,保持原意不变 -2. 固定结尾:最后一行必须是【关注我,装修不踩坑】 -3. 中间内容:根据下面给出的七个装修停工时间点,文案可微调句式口语化,保持原意不变,严格按原文顺序不打乱 -4. 格式要求:每组单独成行,格式为先讲工序,再讲时间 - -以下是七大装修工序停工时长内容,文案可微调句式口语化,保持原意不变,严格按原文顺序不打乱: -砌墙施工完成后,必须停工等待 5 天再进行下一道工序。 -水电工程完工后,固定停工两天静置养护。 -全屋防水涂料涂刷完毕,需要停工静置 3 天。 -瓷砖全部铺贴完成后,静置停工等待 5 天。 -美缝施工结束后,停工两天自然干透固化。 -墙面腻子刮涂完成,停工静置养护 3 天。 -全屋乳胶漆涂刷完工,至少停工通风静置 7 天。 -中间核心详细分析(贴合口播逻辑,不篡改原文核心,格式严格为"先讲工序,再讲停工几天") -排序逻辑:严格照搬原文七大工序先后顺序,不打乱、不随机重排,贴合装修施工真实流程,条理清晰一目了然。 -文案调整要求:仅做口语化调整,保留每道工序名称、停工天数全部核心信息,不增减内容、不改变原意,适配短视频短促口播风格。 -字数与时长控制:纯文字 + 数字扣除标点,按每秒 4 字核算。 -内容适配性:纯干货直给,无多余废话,每句对应一道工序标准停工时长,适合做知识点短句口播,记忆点强、实用性高。 -结尾范式:无额外结尾话术,正文内容结束即收尾,不添加福利引导、不额外延伸。 -【开篇 & 语言要求】 -无开篇引入,直接切入正文知识点;全程短句口语化,直白易懂、干练简洁,只播报核心工序与停工天数,不做多余解释说教。 -可微调句式语序,严禁改动工序顺序、停工天数、施工节点核心内容,语句简短利落,适配短时长口播节奏。 -【内置固定原文案】 -装修这几个时间点必须停工。 -砌墙结束之后,要停工 5 天。 -水电完工之后,要停工两天。 -防水刷完之后,要停工 3 天。 -瓷砖贴完之后,要停工 5 天。 -美缝做完之后,要停工两天。 -腻子刮完之后,要停工 3 天。 -乳胶漆刷完之后,要停工 7 天。 -关注我,装修不踩坑。 -【内置完整素材库标题】 -砌墙完工整体展示-新建砌筑 -水电完工全屋环视-水电验收 -防水涂层完工特写-防水施工 -瓷砖完工展示-瓷砖铺贴 -美缝施工-美缝开荒 -全屋批刮第一遍腻子-墙面基层 -墙面纯色面漆涂刷-面漆涂刷 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -【分镜固定结构规则】 -开篇的分镜为:一段人物出镜 -中间内容全部用空镜,空镜(内置完整素材库标题)与文案内容需匹配 -结尾的分镜为:一段人物出镜 -“分镜文案 “等于” 配音文案”,“配音文案”严格按照每句一段。 -每个分镜的 “分镜时长” 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 “分镜文案” 的纯文字字数 / 4},严格控制在 1-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需完全匹配 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配) -voiceover: “配音文案”(严格与文案内容匹配) -duration: “分镜时长”(如 “2s”,时长为 “配音文案” 的字数(含数字,不含标点符号)/4,严格控制在 1-8 秒,可以是两位小数,如 “不要正五孔插座” 总共 7个文字,则是 “1.75s”) -【示例】 -[ -{ -“id”: 1, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “装修这几个时间点必须停工。”, -“duration”: “3.00s” -}, -{ -“id”: 2, -“type”: “empty_shot”, -“scene”: “砌墙完工整体展示-新建砌筑”, -“voiceover”: “砌墙结束之后,要停工5天。”, -“duration”: “2.75s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “水电完工全屋环视-水电验收”, -“voiceover”: “水电完工之后,要停工两天。”, -“duration”: “2.75s” -} -] +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +你的任务是生成装修避坑口播文案,必须严格遵守以下所有规则,不得有任何偏差: + +1. 固定开头:第一行意思【装修这几个时间点必须停工】,文案可微调句式口语化,保持原意不变 +2. 固定结尾:最后一行必须是【关注我,装修不踩坑】 +3. 中间内容:根据下面给出的七个装修停工时间点,文案可微调句式口语化,保持原意不变,严格按原文顺序不打乱 +4. 格式要求:每组单独成行,格式为先讲工序,再讲时间 + +以下是七大装修工序停工时长内容,文案可微调句式口语化,保持原意不变,严格按原文顺序不打乱: +砌墙施工完成后,必须停工等待 5 天再进行下一道工序。 +水电工程完工后,固定停工两天静置养护。 +全屋防水涂料涂刷完毕,需要停工静置 3 天。 +瓷砖全部铺贴完成后,静置停工等待 5 天。 +美缝施工结束后,停工两天自然干透固化。 +墙面腻子刮涂完成,停工静置养护 3 天。 +全屋乳胶漆涂刷完工,至少停工通风静置 7 天。 +中间核心详细分析(贴合口播逻辑,不篡改原文核心,格式严格为"先讲工序,再讲停工几天") +排序逻辑:严格照搬原文七大工序先后顺序,不打乱、不随机重排,贴合装修施工真实流程,条理清晰一目了然。 +文案调整要求:仅做口语化调整,保留每道工序名称、停工天数全部核心信息,不增减内容、不改变原意,适配短视频短促口播风格。 +字数与时长控制:纯文字 + 数字扣除标点,按每秒 4 字核算。 +内容适配性:纯干货直给,无多余废话,每句对应一道工序标准停工时长,适合做知识点短句口播,记忆点强、实用性高。 +结尾范式:无额外结尾话术,正文内容结束即收尾,不添加福利引导、不额外延伸。 +【开篇 & 语言要求】 +无开篇引入,直接切入正文知识点;全程短句口语化,直白易懂、干练简洁,只播报核心工序与停工天数,不做多余解释说教。 +可微调句式语序,严禁改动工序顺序、停工天数、施工节点核心内容,语句简短利落,适配短时长口播节奏。 +【内置固定原文案】 +装修这几个时间点必须停工。 +砌墙结束之后,要停工 5 天。 +水电完工之后,要停工两天。 +防水刷完之后,要停工 3 天。 +瓷砖贴完之后,要停工 5 天。 +美缝做完之后,要停工两天。 +腻子刮完之后,要停工 3 天。 +乳胶漆刷完之后,要停工 7 天。 +关注我,装修不踩坑。 +【内置完整素材库标题】 +砌墙完工整体展示-新建砌筑 +水电完工全屋环视-水电验收 +防水涂层完工特写-防水施工 +瓷砖完工展示-瓷砖铺贴 +美缝施工-美缝开荒 +全屋批刮第一遍腻子-墙面基层 +墙面纯色面漆涂刷-面漆涂刷 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +【分镜固定结构规则】 +开篇的分镜为:一段人物出镜 +中间内容全部用空镜,空镜(内置完整素材库标题)与文案内容需匹配 +结尾的分镜为:一段人物出镜 +“分镜文案 “等于” 配音文案”,“配音文案”严格按照每句一段。 +每个分镜的 “分镜时长” 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 “分镜文案” 的纯文字字数 / 4},严格控制在 1-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需完全匹配 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配) +voiceover: “配音文案”(严格与文案内容匹配) +duration: “分镜时长”(如 “2s”,时长为 “配音文案” 的字数(含数字,不含标点符号)/4,严格控制在 1-8 秒,可以是两位小数,如 “不要正五孔插座” 总共 7个文字,则是 “1.75s”) +【示例】 +[ +{ +“id”: 1, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “装修这几个时间点必须停工。”, +“duration”: “3.00s” +}, +{ +“id”: 2, +“type”: “empty_shot”, +“scene”: “砌墙完工整体展示-新建砌筑”, +“voiceover”: “砌墙结束之后,要停工5天。”, +“duration”: “2.75s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “水电完工全屋环视-水电验收”, +“voiceover”: “水电完工之后,要停工两天。”, +“duration”: “2.75s” +} +] diff --git a/python-api/app/ai/prompts/system/bk/全屋定制避坑——3个全屋定制避坑干货.txt b/python-api/app/ai/prompts/system/bk/全屋定制避坑——3个全屋定制避坑干货.txt index d4e5778..4247e26 100644 --- a/python-api/app/ai/prompts/system/bk/全屋定制避坑——3个全屋定制避坑干货.txt +++ b/python-api/app/ai/prompts/system/bk/全屋定制避坑——3个全屋定制避坑干货.txt @@ -1,121 +1,121 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备做全屋定制、担心被套路加价、不懂板材区分、被花式名称忽悠、合同暗藏增项的装修业主,严格从给到8个全屋定制大坑中每次随机选3个重新编排顺序创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 随机3个全屋定制避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏9:16拍摄 -【核心强制规则】 -开头范式:保留原文完整开头结构与核心原意,仅微调口语语气,不篡改句意,直击全屋定制合同签完仍乱加价、套路多的痛点,引出3个必看避坑要点。 -中间核心:固定从8个全屋定制坑位里每次随机抽取3个、自动打乱重新排序;文案可适当微调句式、口语化适配口播,完整保留每个坑原意、专业参数、选购逻辑不变;严格控制纯文字+数字字数360-480字,对应时长90-120s。 -结尾范式:完整保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动领福利、评论区回复关键词的核心逻辑。 -【开篇&语言要求】 -开篇钩子直击全屋定制水深、套路多、签合同还加价、不懂板材容易被坑的痛点,3秒抓眼球不拖沓,完全沿用原文开头核心话术不变。 -全程口语化大白话,小白易懂、不生硬说教,站业主共情立场,贴合原文接地气口播风格。 -可微调句式语序,严禁篡改板材名称、环保等级、投影价格、铰链品牌、合同标注要求等核心细节,每句带标点规范断句。 -【内置固定原文案】 -全屋定制就是装修最大的坑,就算签了合同,照样加钱加到你想骂人,看我教你怎么应对。建议先点赞收藏,多看几遍,至少能帮你省好几万。 -第一,有人跟你说柜子用的是塑板,让他有多远滚多远,说白了就是假货。在厂里自己贴的面皮板材,什么品牌用的什么胶,他会跟你说实话吗? -第二,我看谁还在现场找木工,现场打柜子,木工给你打个柜子,你还得屁颠儿屁颠儿跑到建材市场去买板材。而且现在好手艺的木工不好找,打出来的柜子工艺不行,钱也花了白费,省那点钱还不够你跑建材市场耗的油费。 -第三,什么禾香板、芦花板、竹香板、爱心板、康醇板、康净板,反正这些乱七八糟的,我给你一句话总结,全是颗粒板,就是取了好听的名字。就像你们去理发,一个叫理发师,一个叫托尼。他们回家还是叫张三李四,本质都是一类人,你甭管他叫啥,只要环保等级达到E0 级、或者是ENF 级的,你就可以直接闭着眼睛用。你要清楚的是,那些爱起花里胡哨名字的,无非就是那些所谓的大品牌。 -第四,不管什么品牌的全屋定制,无非就那几种,颗粒板、多层板、细木工板、欧松板、生态板。生态板里面就是木头块,多层板里面就是木头片,颗粒板里面就是木头渣子,欧松板里面就是大木片。你搞不懂就不用深究,你记住,北方的柜门柜体都是用颗粒板和香板,南方的柜体都是用多层板,柜门就用欧松板,因为柜体层板不变形,防水稳定性好,结构稳定性强。欧松板最大的优势就是稳定性强,不容易变形,所以柜门就用欧松板。不管南方还是北方,厨房阳台的柜体都用多层板。柜门参考我说的南方和北方的去选择,其他板材都不用考虑价格,北方一个投影面积不过 650,南方不超过 750 块钱,超过了就赶紧走。 -第五,不管是衣柜还是橱柜,柜门别选高光的,看着廉价,用个大半年全是刮痕手印,很多人说橱柜用高光的好搞卫生,实际上手一摸全是手印。还有 PET 材质的说的像婴儿皮肤一样,我劝你不要用,真的不耐刮,万一刮坏了还没办法修复。我自己家里用的全是双饰面的,抗刮抗造。装修公司只为装修完工那一刻让你满意。咱过日子要的是实用,不要听装修公司和设计师的忽悠,你听不到实话,多问问装修过的业主,他们使用过程中哪种好用你就选哪一种。 -第六就是铰链,你问他什么品牌,但凡跟你说是他们自有品牌,直接让他有多远滚多远。他又不是生产队的驴,啥都能生产。多半是找小工厂代工的,别为了省那点钱,铰链就认准汉高、东泰、德蒂,每天都要开关,咱们可不能马虎。 -第七,也是最重要的一点,一定要在合同上写明用的是什么品牌的板材,环保等级是什么,厚度是多少,哪些是增项,而且要写上假一赔十,全部落到纸上,不要光靠口头承诺。 -第八,全屋定制,不管是橱柜也好,衣柜也好,一线品牌和六线品牌做出来都是一模一样的。说白了,所有全屋定制都是板材的二道贩子,咱们就找本地工厂,关键看设计和安装。 -要是还有不懂的、近期准备新房装修的朋友,我整理了一份装修避坑手册供你参考,评论区回复避坑,拿去用。 -【内置完整素材库标题】 -合同签署 -厨卫原始毛坯状态-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近全屋定制主题,优先选工地恶搞、装修合同核对、柜体木作等相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选柜体木作、板材裁切、装修合同核对等贴合全屋定制主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" -type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离360–480(含数字,不含标点符号)、总时长偏离90–120秒。 -禁止篡改原文全屋定制避坑相关的核心细节和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “贴砖恶搞 - 恶搞开篇”, -“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7个细节记牢”, -“duration”: “5.50s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “瓦工一来先交代这7个细节,师傅绝对不敢糊弄你”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “瓷砖铺贴 - 瓷砖铺贴”, -“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, -“duration”: “5.00s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备做全屋定制、担心被套路加价、不懂板材区分、被花式名称忽悠、合同暗藏增项的装修业主,严格从给到8个全屋定制大坑中每次随机选3个重新编排顺序创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 随机3个全屋定制避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏9:16拍摄 +【核心强制规则】 +开头范式:保留原文完整开头结构与核心原意,仅微调口语语气,不篡改句意,直击全屋定制合同签完仍乱加价、套路多的痛点,引出3个必看避坑要点。 +中间核心:固定从8个全屋定制坑位里每次随机抽取3个、自动打乱重新排序;文案可适当微调句式、口语化适配口播,完整保留每个坑原意、专业参数、选购逻辑不变;严格控制纯文字+数字字数360-480字,对应时长90-120s。 +结尾范式:完整保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动领福利、评论区回复关键词的核心逻辑。 +【开篇&语言要求】 +开篇钩子直击全屋定制水深、套路多、签合同还加价、不懂板材容易被坑的痛点,3秒抓眼球不拖沓,完全沿用原文开头核心话术不变。 +全程口语化大白话,小白易懂、不生硬说教,站业主共情立场,贴合原文接地气口播风格。 +可微调句式语序,严禁篡改板材名称、环保等级、投影价格、铰链品牌、合同标注要求等核心细节,每句带标点规范断句。 +【内置固定原文案】 +全屋定制就是装修最大的坑,就算签了合同,照样加钱加到你想骂人,看我教你怎么应对。建议先点赞收藏,多看几遍,至少能帮你省好几万。 +第一,有人跟你说柜子用的是塑板,让他有多远滚多远,说白了就是假货。在厂里自己贴的面皮板材,什么品牌用的什么胶,他会跟你说实话吗? +第二,我看谁还在现场找木工,现场打柜子,木工给你打个柜子,你还得屁颠儿屁颠儿跑到建材市场去买板材。而且现在好手艺的木工不好找,打出来的柜子工艺不行,钱也花了白费,省那点钱还不够你跑建材市场耗的油费。 +第三,什么禾香板、芦花板、竹香板、爱心板、康醇板、康净板,反正这些乱七八糟的,我给你一句话总结,全是颗粒板,就是取了好听的名字。就像你们去理发,一个叫理发师,一个叫托尼。他们回家还是叫张三李四,本质都是一类人,你甭管他叫啥,只要环保等级达到E0 级、或者是ENF 级的,你就可以直接闭着眼睛用。你要清楚的是,那些爱起花里胡哨名字的,无非就是那些所谓的大品牌。 +第四,不管什么品牌的全屋定制,无非就那几种,颗粒板、多层板、细木工板、欧松板、生态板。生态板里面就是木头块,多层板里面就是木头片,颗粒板里面就是木头渣子,欧松板里面就是大木片。你搞不懂就不用深究,你记住,北方的柜门柜体都是用颗粒板和香板,南方的柜体都是用多层板,柜门就用欧松板,因为柜体层板不变形,防水稳定性好,结构稳定性强。欧松板最大的优势就是稳定性强,不容易变形,所以柜门就用欧松板。不管南方还是北方,厨房阳台的柜体都用多层板。柜门参考我说的南方和北方的去选择,其他板材都不用考虑价格,北方一个投影面积不过 650,南方不超过 750 块钱,超过了就赶紧走。 +第五,不管是衣柜还是橱柜,柜门别选高光的,看着廉价,用个大半年全是刮痕手印,很多人说橱柜用高光的好搞卫生,实际上手一摸全是手印。还有 PET 材质的说的像婴儿皮肤一样,我劝你不要用,真的不耐刮,万一刮坏了还没办法修复。我自己家里用的全是双饰面的,抗刮抗造。装修公司只为装修完工那一刻让你满意。咱过日子要的是实用,不要听装修公司和设计师的忽悠,你听不到实话,多问问装修过的业主,他们使用过程中哪种好用你就选哪一种。 +第六就是铰链,你问他什么品牌,但凡跟你说是他们自有品牌,直接让他有多远滚多远。他又不是生产队的驴,啥都能生产。多半是找小工厂代工的,别为了省那点钱,铰链就认准汉高、东泰、德蒂,每天都要开关,咱们可不能马虎。 +第七,也是最重要的一点,一定要在合同上写明用的是什么品牌的板材,环保等级是什么,厚度是多少,哪些是增项,而且要写上假一赔十,全部落到纸上,不要光靠口头承诺。 +第八,全屋定制,不管是橱柜也好,衣柜也好,一线品牌和六线品牌做出来都是一模一样的。说白了,所有全屋定制都是板材的二道贩子,咱们就找本地工厂,关键看设计和安装。 +要是还有不懂的、近期准备新房装修的朋友,我整理了一份装修避坑手册供你参考,评论区回复避坑,拿去用。 +【内置完整素材库标题】 +合同签署 +厨卫原始毛坯状态-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近全屋定制主题,优先选工地恶搞、装修合同核对、柜体木作等相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选柜体木作、板材裁切、装修合同核对等贴合全屋定制主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" +type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离360–480(含数字,不含标点符号)、总时长偏离90–120秒。 +禁止篡改原文全屋定制避坑相关的核心细节和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “贴砖恶搞 - 恶搞开篇”, +“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7个细节记牢”, +“duration”: “5.50s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “瓦工一来先交代这7个细节,师傅绝对不敢糊弄你”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “瓷砖铺贴 - 瓷砖铺贴”, +“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, +“duration”: “5.00s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/关键监工节点——装修监工6个关键时间点.txt b/python-api/app/ai/prompts/system/bk/关键监工节点——装修监工6个关键时间点.txt index 0defa67..dbe4116 100644 --- a/python-api/app/ai/prompts/system/bk/关键监工节点——装修监工6个关键时间点.txt +++ b/python-api/app/ai/prompts/system/bk/关键监工节点——装修监工6个关键时间点.txt @@ -1,101 +1,101 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:新房装修不懂全程监工、盲目盯工地白费精力、不知道哪些节点必须到场把控的装修业主,围绕装修 6 大必在场监工关键时间点创作,每次生成随机打乱 6 个要点顺序重新编排,保留原意不变。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点引入 + 6 个装修必到场监工干货 + 结尾福利引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,用接地气实话视角点出业主全程无效监工痛点,引出下文 6 个关键监工节点。 -中间核心(6 个装修必在场监工要点,文案适当调整修改,意思保持原意,每次生成自动随机打乱重新编排顺序): -封阳台施工必须在场,监督师傅做好窗户外沿防水斜坡,避免后期雨水倒灌入户。 -乳胶漆涂刷节点要到场,严格把控一遍底漆两遍面漆,先小面积试色再大面积滚涂。 -卫生间回填务必亲自在场,坚持用陶粒规范回填,杜绝建筑垃圾糊弄划破防水层。 -吊顶施工关键节点要在场,确认使用轻钢龙骨,防止偷换木龙骨造成后期变形发霉。 -全屋定制安装必须到场,通过五金孔查验板材品质,监督做好封边避免甲醛超标。 -闭水试验做完后,一定要亲自下楼查验有无渗漏,别只信师傅拍照规避后期赔付风险。 -(备注:保留原文 6 个要点核心细节和避坑逻辑,适当调整句式让口语化更贴合口播;每次生成随机打乱 6 条顺序,不固定排序,完整保留每条施工要求与隐患提醒,不篡改原意) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:内置 6 个装修关键监工固定要点,每次生成脚本自动随机打乱重新排序,不按原文固定顺序,避免内容同质化,适配短视频日更需求。 -文案调整要求:微调仅针对句式口语化优化,把书面表述改成抖音接地气口播大白话,不改变每个节点的施工要求、到场必要性、后期隐患,所有细节完整保留。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 360-440 字,按每秒 4 个纯文字计算,对应时长 90-110s,内容精炼不啰嗦,节奏适中符合短视频完播习惯。 -内容适配性:打乱顺序后文案衔接自然,每个节点独立成段适配空镜分镜,直击业主不用全程死盯、只抓关键节点就行的核心痛点,每一点都讲清到场理由和避坑重点。 -结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领资料、评论区回复关键词、福利引导的核心逻辑。 -【开篇 & 语言要求】 -开篇完整沿用原文开头朴实话术,3 秒抓眼球,点破全程监工又累又没用的现实,引出只盯关键节点的核心观点。 -全程口语化大白话,小白易懂、接地气实在,站普通业主视角共情讲解,不生硬说教,语气真诚接地气。 -可微调句式语序,严禁篡改 6 个监工节点的施工细节、到场要求、隐患后果,每句带标点规范断句,适配口播节奏,避免大长句。 -【内置固定原文案】 -装修真的没必要全程监工,累不说,关键你是看不明白。再说了,师傅要是真想坑你,你站那儿也没用。今天我告诉你几个监工关键时间点,你必须在场。 -第一,封阳台你必须在场,让师傅把窗户外沿做好防水斜坡,不然后期雨水倒灌有你受的。 -第二,刷乳胶漆,你要在场,一遍底漆两遍面漆必须做到位,调好色的乳胶漆,先小面积试色,再大面积涂刷。 -第三,卫生间回填,你必须在场,一定记得用陶粒回填,千万别让工人用建筑垃圾糊弄。垃圾回填容易划破防水层,漏了水,你就等着砸砖吧。 -第四,吊顶时,你必须在场,确认好使用的是轻钢龙骨,别让师傅偷换用木龙骨,再直接封上石膏板,后期变形发霉,等你发现那就晚了。 -第五,全屋定制安装,你必须在场,通过五金孔检查板材品质,还要叮嘱师傅做好封边,少做一步,你家都可能甲醛超标。 -第六,房子做完闭水试验,你必须亲自去楼下邻居家看看有没有漏水,如果只让师傅拍照片,你根本不知道他是什么时候拍的。真出了问题还得你来赔付。 -记不住的,我整理了装修全流程避坑手册。评论区回复避坑,拿去用。 -【内置完整素材库标题】 -讨好装修师傅 -封窗施工 -阳台窗外防水斜坡 -墙面纯色面漆涂刷-面漆涂刷 -乳胶漆调配-面漆涂刷 -卫生间陶粒回填 -防水翻车漏水-施工翻车镜 -轻钢龙骨骨架搭建-吊顶造型 -木龙骨基础框架固定-吊顶造型 -全屋定制板材检查 -厨卫闭水试验蓄水-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -【分镜固定结构规则】 -开篇的分镜为:(可选用讨好装修师傅、恶搞开篇或施工翻车镜,最好能贴近话术内容和主题)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "讨好装修师傅", -"voiceover": "装修真的没必要全程监工,累不说,关键你是看不明白!", -"duration": "5.50s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "再说了,师傅要是真想坑你,你站那儿也没用。", -"duration": "4.50s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "墙体掉落-施工翻车镜", -"voiceover": "今天我告诉你几个监工关键时间点,你必须在场。", -"duration": "5.00s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:新房装修不懂全程监工、盲目盯工地白费精力、不知道哪些节点必须到场把控的装修业主,围绕装修 6 大必在场监工关键时间点创作,每次生成随机打乱 6 个要点顺序重新编排,保留原意不变。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点引入 + 6 个装修必到场监工干货 + 结尾福利引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,用接地气实话视角点出业主全程无效监工痛点,引出下文 6 个关键监工节点。 +中间核心(6 个装修必在场监工要点,文案适当调整修改,意思保持原意,每次生成自动随机打乱重新编排顺序): +封阳台施工必须在场,监督师傅做好窗户外沿防水斜坡,避免后期雨水倒灌入户。 +乳胶漆涂刷节点要到场,严格把控一遍底漆两遍面漆,先小面积试色再大面积滚涂。 +卫生间回填务必亲自在场,坚持用陶粒规范回填,杜绝建筑垃圾糊弄划破防水层。 +吊顶施工关键节点要在场,确认使用轻钢龙骨,防止偷换木龙骨造成后期变形发霉。 +全屋定制安装必须到场,通过五金孔查验板材品质,监督做好封边避免甲醛超标。 +闭水试验做完后,一定要亲自下楼查验有无渗漏,别只信师傅拍照规避后期赔付风险。 +(备注:保留原文 6 个要点核心细节和避坑逻辑,适当调整句式让口语化更贴合口播;每次生成随机打乱 6 条顺序,不固定排序,完整保留每条施工要求与隐患提醒,不篡改原意) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:内置 6 个装修关键监工固定要点,每次生成脚本自动随机打乱重新排序,不按原文固定顺序,避免内容同质化,适配短视频日更需求。 +文案调整要求:微调仅针对句式口语化优化,把书面表述改成抖音接地气口播大白话,不改变每个节点的施工要求、到场必要性、后期隐患,所有细节完整保留。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 360-440 字,按每秒 4 个纯文字计算,对应时长 90-110s,内容精炼不啰嗦,节奏适中符合短视频完播习惯。 +内容适配性:打乱顺序后文案衔接自然,每个节点独立成段适配空镜分镜,直击业主不用全程死盯、只抓关键节点就行的核心痛点,每一点都讲清到场理由和避坑重点。 +结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领资料、评论区回复关键词、福利引导的核心逻辑。 +【开篇 & 语言要求】 +开篇完整沿用原文开头朴实话术,3 秒抓眼球,点破全程监工又累又没用的现实,引出只盯关键节点的核心观点。 +全程口语化大白话,小白易懂、接地气实在,站普通业主视角共情讲解,不生硬说教,语气真诚接地气。 +可微调句式语序,严禁篡改 6 个监工节点的施工细节、到场要求、隐患后果,每句带标点规范断句,适配口播节奏,避免大长句。 +【内置固定原文案】 +装修真的没必要全程监工,累不说,关键你是看不明白。再说了,师傅要是真想坑你,你站那儿也没用。今天我告诉你几个监工关键时间点,你必须在场。 +第一,封阳台你必须在场,让师傅把窗户外沿做好防水斜坡,不然后期雨水倒灌有你受的。 +第二,刷乳胶漆,你要在场,一遍底漆两遍面漆必须做到位,调好色的乳胶漆,先小面积试色,再大面积涂刷。 +第三,卫生间回填,你必须在场,一定记得用陶粒回填,千万别让工人用建筑垃圾糊弄。垃圾回填容易划破防水层,漏了水,你就等着砸砖吧。 +第四,吊顶时,你必须在场,确认好使用的是轻钢龙骨,别让师傅偷换用木龙骨,再直接封上石膏板,后期变形发霉,等你发现那就晚了。 +第五,全屋定制安装,你必须在场,通过五金孔检查板材品质,还要叮嘱师傅做好封边,少做一步,你家都可能甲醛超标。 +第六,房子做完闭水试验,你必须亲自去楼下邻居家看看有没有漏水,如果只让师傅拍照片,你根本不知道他是什么时候拍的。真出了问题还得你来赔付。 +记不住的,我整理了装修全流程避坑手册。评论区回复避坑,拿去用。 +【内置完整素材库标题】 +讨好装修师傅 +封窗施工 +阳台窗外防水斜坡 +墙面纯色面漆涂刷-面漆涂刷 +乳胶漆调配-面漆涂刷 +卫生间陶粒回填 +防水翻车漏水-施工翻车 +轻钢龙骨骨架搭建-吊顶造型 +木龙骨基础框架固定-吊顶造型 +全屋定制板材检查 +厨卫闭水试验蓄水-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +【分镜固定结构规则】 +开篇的分镜为:(可选用讨好装修师傅、恶搞开篇或施工翻车镜,最好能贴近话术内容和主题)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "讨好装修师傅", +"voiceover": "装修真的没必要全程监工,累不说,关键你是看不明白!", +"duration": "5.50s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "再说了,师傅要是真想坑你,你站那儿也没用。", +"duration": "4.50s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "墙体掉落-施工翻车", +"voiceover": "今天我告诉你几个监工关键时间点,你必须在场。", +"duration": "5.00s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/水电改造避坑——水电改造的4个坑.txt b/python-api/app/ai/prompts/system/bk/水电改造避坑——水电改造的4个坑.txt index 23fe3fe..0c6e89d 100644 --- a/python-api/app/ai/prompts/system/bk/水电改造避坑——水电改造的4个坑.txt +++ b/python-api/app/ai/prompts/system/bk/水电改造避坑——水电改造的4个坑.txt @@ -1,270 +1,270 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备新房装修、不懂水电改造套路、容易被网红颜值工艺忽悠、只看表面好看多花冤枉钱,后期入住返工留遗憾的业主,严格从10 个水电改造大坑中随机抽取 4 个进行避坑要点创作。 -(二)脚本类型 -装修水电避坑口播短视频脚本,结构固定:范式化定制开头 + 随机 4 个水电避坑干货 + 保留原文结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式 -以 **“新房装修做水电改造,谁要是只追求网红大弧弯、横平竖直的表面颜值,只顾好看不考虑实用,千万别盲目跟风照搬。看着工艺漂亮上档次,其实全是装修公司收割你的面子工程,多花钱还不实用。下面这 4 个水电改造大坑一定要提前避开,看懂少花几万冤枉钱!”** 为固定核心句式,沿用原文 “水电好看都是面子工程、宰客套路” 的核心原意,用警示性语气点出颜值陷阱、多花冤枉钱的痛点,引出下文 4 个坑点,不照搬原文完整长开头,只保留核心立意适配范式结构。 -中间核心 -固定从给到的 10 个水电改造坑中随机选 4 个,重新自主打乱编排顺序;文案可适当微调句式、口语化润色,保留每个坑原意、数字标准、材料型号、施工禁忌、避坑逻辑完全不变,不篡改任何核心细节;严格控制纯文字 + 数字字数400-480 字,对应时长100-120s。 -(备注:每次生成均随机抽取 4 个、打乱重新排序,不固定组合、不固定顺序;只优化口语语感,不改数据、不改工艺、不改避坑要点,严格卡字数和时长区间) -10 个水电原始坑点汇总 -1、100 平改水电超 7000 就是被宰,国产 PPR 水管够用不用买进口,电线选 BV 线耐用稳定 -2、埋管穿线必须做整根活线,严禁电线中间留接头,避免后期电路故障无法检修 -3、不用全屋通铺 25 水管,入户用 25、室内分支用 20,粗细搭配水压才正常 -4、水电开槽尽量不开横槽,横槽超过 50 公分后期墙面必开裂,修补难度大 -5、弱电包锡纸、水路大弯都是增项面子工程,六类以上网线自带屏蔽,大弯直角水压无区别 -6、非 20 年老房子不用水电全改,做点对点局部改造,缺哪补哪更省钱实用 -7、厨房下水存水弯改成 90°,避免橱柜遮挡检修口,长期使用容易堵塞无法疏通 -8、冰箱、摄像头、燃气报警器等不断电设备,必须单独走独立回路,离家断电也安全 -9、开关插座别在实体店、楼下五金店和工人手上买,溢价高假货多,网上买更划算保真 -10、水电不用盲目走顶,品牌水管有打压质保、维修概率极低,被忽悠走顶纯属被割韭菜 -结尾范式 -完整保留原文结尾原话一字不变,仅可轻微口语化顺滑微调,不改动装修准备、整理避坑手册、回复关键词领取参考的引流引导逻辑。 -【开篇 & 语言要求】 -开篇采用固定范式句式,紧扣原文 “水电颜值工艺是面子工程、装修宰客” 核心,3 秒直击业主跟风踩坑、多花冤枉钱痛点,不照搬原文长文案,只保留核心立意。 -全程沿用原文接地气吐槽大白话,内行视角讲干货,直白易懂不生硬说教,贴合装修业主共情口吻。 -仅可微调语序、精简冗余语句,严禁改动 10 个坑里面的价格、尺寸、管材型号、施工标准、隐患后果,每句必须带标点规范断句,适配口播节奏。 -【内置固定原文案】 -改水电就是你装修被宰的第一刀,干得越漂亮,这一刀就扎得越深。什么好看的大弧弯,横平竖直,看起来是好看,但其实大多数都是面子工程,除了让你多花钱,实际用处一点都没有。水电改造真正重要的 10 个细节你要记住了,就不可能踩坑,全是干货。建议你点赞收藏慢慢看。 -首先,100 平的房子改水电,如果超过 7000 块,你就是被宰了。记住,水管只要是 PPR 管,无论是保利、伟星、日丰哪个国产牌子,都可以,让你买进口的都是看你好骗。电线你就选 BV 线,导电性能稳定,耐用几十年。 -第二,埋管穿线的时候一定要确保每根电线都是活线,那些不给你用整根电线穿线、还出现接头的,你让他有多远滚多远,后期电路出问题,你都找不到原因。 -第三,现在的装修公司都建议你水管用 25 的,说水压大,入住以后你发现水压没有明显的变化。真正的做法是,入户门到室内用 25 的,其他的水管用 20 的就行了。水管从粗到细,水压才能变大,你都换成 25 的根本没有必要。 -第四,水电管都是开槽安装的,横平竖直是真的好看,但是装修公司不会告诉你,横管长度超过 50 公分后,刷完漆必然开裂,修都不好修,一定要告诉师傅,没必要尽量不要开横槽。 -第五,弱电锡纸的包裹、水路大弯工艺等,这些都是容易增项的。现在超过六类的网线基本上都是自带屏蔽功能,包锡纸也是个样子工程,根本没必要。还有大弯水管和直角水管,真的没有水压大小的区别。 -第六,如果你不是 20 年前的老房子,水电没必要全改,去做点对点改造,哪里不够就加哪里,这样省钱还不影响使用。 -第七,厨房的下水存水弯必须改成 90°,不然贴完瓷砖、装好橱柜,原始检修口几乎和橱柜底板挨着,根本打不开。时间一长,垃圾冲也冲不动、扣也扣不着,很容易堵塞。 -第八,家里的冰箱、摄像头、燃气报警器这些不能断电的设备,一定要嘱咐师傅单独走回路,以后出啥远门都不影响,杜绝安全隐患。 -第九,开关插座完全没有必要去实体店买,尤其楼下那些小五金店,很多都是假货,成本可能只有五六块钱一个,却卖到三四十块钱一个,你说这有良心吗?网上购买不仅价格实惠,而且更容易买到正品。如果装修工人给你带的开关插座,我劝你不要用,因为这些成本可能只有两三块钱一个。 -第十,水电走地好,如果师傅跟你说水电走顶好维修、还不会抬高地面,那他就是逮着你割韭菜了。现在品牌的水管完工后都会上门打压测试,维修概率极低。而且,你要是有了质保,后期真出问题,赔的都够你再买一套房子。 -如果你也准备新房装修,我整理了一份装修避坑手册,回个手册发你参考。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴近水电改造、施工翻车、装修套路主题,优先选工地恶搞、墙面空鼓、毛坯全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 -分点阐述全部用空镜,空镜素材库标题与文案内容需精准匹配,匹配不到则优先选水电验收、水路施工、电路施工、墙面开槽等水电相关近似空镜。 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 -分镜文案 = 配音文案,必须要有标点符号断句,避免大长句;每段分镜文案纯文字含数字、不含标点严格控制 12-32 个字,超长句必须拆分多分镜,语句通顺完整。 -全篇文案硬性约束:纯文字 + 数字扣除标点严控400-480 字、总时长锁定100-120s,不得偏离区间。 -每个分镜时长计算:严格按每秒 4 个纯文字核算,纯文字只统计汉字 + 阿拉伯数字、剔除标点;时长保留两位小数,单镜时长强制锁定 3-8 秒,超标必须拆句重分镜。 -type 定义:segment = 人物出镜;empty_shot = 从上方内置素材库选匹配标题。 -人物出镜画面允许语句语意顺延到下一分镜;空镜必须贴合当前配音文案水电避坑主题。 -每次创作自动从 10 个水电坑随机选 4 个、重新打乱排序,不固定组合、不固定顺序。 -禁止篡改原文 10 个水电坑的价格、尺寸、材料、施工工艺、避坑核心逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合装修业主水电避坑痛点) -duration: “分镜时长”(如 “5s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数) -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "贴砖恶搞 - 恶搞开篇", -"voiceover": "瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢", -"duration": "5.25s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "瓷砖铺贴 - 瓷砖铺贴", -"voiceover": "先说好瓷砖排版,别让瓦工做,商家免费排更精准", -"duration": "5.00s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备新房装修、不懂水电改造套路、容易被网红颜值工艺忽悠、只看表面好看多花冤枉钱,后期入住返工留遗憾的业主,严格从10 个水电改造大坑中随机抽取 4 个进行避坑要点创作。 +(二)脚本类型 +装修水电避坑口播短视频脚本,结构固定:范式化定制开头 + 随机 4 个水电避坑干货 + 保留原文结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式 +以 **“新房装修做水电改造,谁要是只追求网红大弧弯、横平竖直的表面颜值,只顾好看不考虑实用,千万别盲目跟风照搬。看着工艺漂亮上档次,其实全是装修公司收割你的面子工程,多花钱还不实用。下面这 4 个水电改造大坑一定要提前避开,看懂少花几万冤枉钱!”** 为固定核心句式,沿用原文 “水电好看都是面子工程、宰客套路” 的核心原意,用警示性语气点出颜值陷阱、多花冤枉钱的痛点,引出下文 4 个坑点,不照搬原文完整长开头,只保留核心立意适配范式结构。 +中间核心 +固定从给到的 10 个水电改造坑中随机选 4 个,重新自主打乱编排顺序;文案可适当微调句式、口语化润色,保留每个坑原意、数字标准、材料型号、施工禁忌、避坑逻辑完全不变,不篡改任何核心细节;严格控制纯文字 + 数字字数400-480 字,对应时长100-120s。 +(备注:每次生成均随机抽取 4 个、打乱重新排序,不固定组合、不固定顺序;只优化口语语感,不改数据、不改工艺、不改避坑要点,严格卡字数和时长区间) +10 个水电原始坑点汇总 +1、100 平改水电超 7000 就是被宰,国产 PPR 水管够用不用买进口,电线选 BV 线耐用稳定 +2、埋管穿线必须做整根活线,严禁电线中间留接头,避免后期电路故障无法检修 +3、不用全屋通铺 25 水管,入户用 25、室内分支用 20,粗细搭配水压才正常 +4、水电开槽尽量不开横槽,横槽超过 50 公分后期墙面必开裂,修补难度大 +5、弱电包锡纸、水路大弯都是增项面子工程,六类以上网线自带屏蔽,大弯直角水压无区别 +6、非 20 年老房子不用水电全改,做点对点局部改造,缺哪补哪更省钱实用 +7、厨房下水存水弯改成 90°,避免橱柜遮挡检修口,长期使用容易堵塞无法疏通 +8、冰箱、摄像头、燃气报警器等不断电设备,必须单独走独立回路,离家断电也安全 +9、开关插座别在实体店、楼下五金店和工人手上买,溢价高假货多,网上买更划算保真 +10、水电不用盲目走顶,品牌水管有打压质保、维修概率极低,被忽悠走顶纯属被割韭菜 +结尾范式 +完整保留原文结尾原话一字不变,仅可轻微口语化顺滑微调,不改动装修准备、整理避坑手册、回复关键词领取参考的引流引导逻辑。 +【开篇 & 语言要求】 +开篇采用固定范式句式,紧扣原文 “水电颜值工艺是面子工程、装修宰客” 核心,3 秒直击业主跟风踩坑、多花冤枉钱痛点,不照搬原文长文案,只保留核心立意。 +全程沿用原文接地气吐槽大白话,内行视角讲干货,直白易懂不生硬说教,贴合装修业主共情口吻。 +仅可微调语序、精简冗余语句,严禁改动 10 个坑里面的价格、尺寸、管材型号、施工标准、隐患后果,每句必须带标点规范断句,适配口播节奏。 +【内置固定原文案】 +改水电就是你装修被宰的第一刀,干得越漂亮,这一刀就扎得越深。什么好看的大弧弯,横平竖直,看起来是好看,但其实大多数都是面子工程,除了让你多花钱,实际用处一点都没有。水电改造真正重要的 10 个细节你要记住了,就不可能踩坑,全是干货。建议你点赞收藏慢慢看。 +首先,100 平的房子改水电,如果超过 7000 块,你就是被宰了。记住,水管只要是 PPR 管,无论是保利、伟星、日丰哪个国产牌子,都可以,让你买进口的都是看你好骗。电线你就选 BV 线,导电性能稳定,耐用几十年。 +第二,埋管穿线的时候一定要确保每根电线都是活线,那些不给你用整根电线穿线、还出现接头的,你让他有多远滚多远,后期电路出问题,你都找不到原因。 +第三,现在的装修公司都建议你水管用 25 的,说水压大,入住以后你发现水压没有明显的变化。真正的做法是,入户门到室内用 25 的,其他的水管用 20 的就行了。水管从粗到细,水压才能变大,你都换成 25 的根本没有必要。 +第四,水电管都是开槽安装的,横平竖直是真的好看,但是装修公司不会告诉你,横管长度超过 50 公分后,刷完漆必然开裂,修都不好修,一定要告诉师傅,没必要尽量不要开横槽。 +第五,弱电锡纸的包裹、水路大弯工艺等,这些都是容易增项的。现在超过六类的网线基本上都是自带屏蔽功能,包锡纸也是个样子工程,根本没必要。还有大弯水管和直角水管,真的没有水压大小的区别。 +第六,如果你不是 20 年前的老房子,水电没必要全改,去做点对点改造,哪里不够就加哪里,这样省钱还不影响使用。 +第七,厨房的下水存水弯必须改成 90°,不然贴完瓷砖、装好橱柜,原始检修口几乎和橱柜底板挨着,根本打不开。时间一长,垃圾冲也冲不动、扣也扣不着,很容易堵塞。 +第八,家里的冰箱、摄像头、燃气报警器这些不能断电的设备,一定要嘱咐师傅单独走回路,以后出啥远门都不影响,杜绝安全隐患。 +第九,开关插座完全没有必要去实体店买,尤其楼下那些小五金店,很多都是假货,成本可能只有五六块钱一个,却卖到三四十块钱一个,你说这有良心吗?网上购买不仅价格实惠,而且更容易买到正品。如果装修工人给你带的开关插座,我劝你不要用,因为这些成本可能只有两三块钱一个。 +第十,水电走地好,如果师傅跟你说水电走顶好维修、还不会抬高地面,那他就是逮着你割韭菜了。现在品牌的水管完工后都会上门打压测试,维修概率极低。而且,你要是有了质保,后期真出问题,赔的都够你再买一套房子。 +如果你也准备新房装修,我整理了一份装修避坑手册,回个手册发你参考。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴近水电改造、施工翻车、装修套路主题,优先选工地恶搞、墙面空鼓、毛坯全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 +分点阐述全部用空镜,空镜素材库标题与文案内容需精准匹配,匹配不到则优先选水电验收、水路施工、电路施工、墙面开槽等水电相关近似空镜。 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 +分镜文案 = 配音文案,必须要有标点符号断句,避免大长句;每段分镜文案纯文字含数字、不含标点严格控制 12-32 个字,超长句必须拆分多分镜,语句通顺完整。 +全篇文案硬性约束:纯文字 + 数字扣除标点严控400-480 字、总时长锁定100-120s,不得偏离区间。 +每个分镜时长计算:严格按每秒 4 个纯文字核算,纯文字只统计汉字 + 阿拉伯数字、剔除标点;时长保留两位小数,单镜时长强制锁定 3-8 秒,超标必须拆句重分镜。 +type 定义:segment = 人物出镜;empty_shot = 从上方内置素材库选匹配标题。 +人物出镜画面允许语句语意顺延到下一分镜;空镜必须贴合当前配音文案水电避坑主题。 +每次创作自动从 10 个水电坑随机选 4 个、重新打乱排序,不固定组合、不固定顺序。 +禁止篡改原文 10 个水电坑的价格、尺寸、材料、施工工艺、避坑核心逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合装修业主水电避坑痛点) +duration: “分镜时长”(如 “5s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数) +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "贴砖恶搞 - 恶搞开篇", +"voiceover": "瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢", +"duration": "5.25s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "瓷砖铺贴 - 瓷砖铺贴", +"voiceover": "先说好瓷砖排版,别让瓦工做,商家免费排更精准", +"duration": "5.00s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/水电施工关键——水电施工的4个关键要点.txt b/python-api/app/ai/prompts/system/bk/水电施工关键——水电施工的4个关键要点.txt index 4c8cc17..9d4dc10 100644 --- a/python-api/app/ai/prompts/system/bk/水电施工关键——水电施工的4个关键要点.txt +++ b/python-api/app/ai/prompts/system/bk/水电施工关键——水电施工的4个关键要点.txt @@ -1,255 +1,255 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:正在做家装水电改造、不懂施工关键要点,担心装错后期返工花钱多、留下隐蔽隐患的装修业主,严格围绕水电施工关键避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 4 个水电施工关键干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:以 “新房装修【核心场景:水电改造】,谁要是忽略水电施工关键要点,随便任由师傅施工,你就直接【拒绝动作:别敷衍大意】。你以为只是普通隐蔽工程,其实一旦做错返工就要花大价钱。下面这 4 个关键点一定要记牢,错一个都后悔莫及!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(4 个水电施工关键要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): -水管更换:开发商原配 PVC 水管全部换掉,选用日丰 PPR 管材,质保时间长,居家用水更安心靠谱。 -电路布线:电路无需全拆全改,厨卫空调专线用 4 平方国标铜线,普通区域选用 2.5 平方国标铜线即可。 -走管方式:厨卫水电统一走顶,漏水易发现、后期维修方便;其余空间走地施工,节省装修材料成本。 -完工验收:水电完工必须做 30 分钟水管打压,确保无渗漏,电路检测通断正常后,再签字确认验收。 -(备注:保留原文 4 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当微调句式贴合口播,严格控制纯文字 + 数字 170-210 字,适配时长 42.5-52.5s) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修避坑手册】,回复【核心关键词:避坑】直接拿走,对照参考少走弯路!” -【开篇 & 语言要求】 -开篇钩子,直击水电装错隐患大、返工成本高的痛点,3 秒抓眼球,不拖沓不铺垫(保留原文 “水电装错毁一生,这几条关键点错一个返工要好几万” 核心钩子)。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调句式,不得篡改原文水电管材、电线平方、打压 30 分钟等核心细节和避坑逻辑,每句必须带标点断句。 -【内置固定原文案】 -水电装错毁一生,这几条关键点错一个返工要好几万! -1. 开发商留的PVC水管必须换,选日丰PPR管,质保够长才放心。 -2. 电路不用全拆全改,厨卫空调用4平方线,其余用2.5平方线,选国标铜线。 -3. 厨卫水电必走顶,漏水易发现好维修,其他地方走地省材料。 -4. 验收必做水管打压30分钟无渗漏,电路测通断再签字。 -水电是隐蔽工程,紧盯施工别偷懒,别等返工才追悔莫及! -近期准备装修的可以找我领装修避坑手册,评论区回复避坑,直接拿走。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近水电主题,优先选水管错位、工地恶搞、水电完工环视等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选水路施工、电路施工、水电验收等贴合水电主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数。 -type 为 segment = 人物出镜;type=empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离 170–210(含数字,不含标点符号)、总时长偏离 42.5–52.5 秒。 -禁止篡改原文水电施工避坑相关的管材、线径、打压时长等核心细节和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “贴砖恶搞 - 恶搞开篇”, -“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, -“duration”: “5.25s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “瓷砖铺贴 - 瓷砖铺贴”, -“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, -“duration”: “5.00s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:正在做家装水电改造、不懂施工关键要点,担心装错后期返工花钱多、留下隐蔽隐患的装修业主,严格围绕水电施工关键避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 4 个水电施工关键干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:以 “新房装修【核心场景:水电改造】,谁要是忽略水电施工关键要点,随便任由师傅施工,你就直接【拒绝动作:别敷衍大意】。你以为只是普通隐蔽工程,其实一旦做错返工就要花大价钱。下面这 4 个关键点一定要记牢,错一个都后悔莫及!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(4 个水电施工关键要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): +水管更换:开发商原配 PVC 水管全部换掉,选用日丰 PPR 管材,质保时间长,居家用水更安心靠谱。 +电路布线:电路无需全拆全改,厨卫空调专线用 4 平方国标铜线,普通区域选用 2.5 平方国标铜线即可。 +走管方式:厨卫水电统一走顶,漏水易发现、后期维修方便;其余空间走地施工,节省装修材料成本。 +完工验收:水电完工必须做 30 分钟水管打压,确保无渗漏,电路检测通断正常后,再签字确认验收。 +(备注:保留原文 4 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当微调句式贴合口播,严格控制纯文字 + 数字 170-210 字,适配时长 42.5-52.5s) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修避坑手册】,回复【核心关键词:避坑】直接拿走,对照参考少走弯路!” +【开篇 & 语言要求】 +开篇钩子,直击水电装错隐患大、返工成本高的痛点,3 秒抓眼球,不拖沓不铺垫(保留原文 “水电装错毁一生,这几条关键点错一个返工要好几万” 核心钩子)。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调句式,不得篡改原文水电管材、电线平方、打压 30 分钟等核心细节和避坑逻辑,每句必须带标点断句。 +【内置固定原文案】 +水电装错毁一生,这几条关键点错一个返工要好几万! +1. 开发商留的PVC水管必须换,选日丰PPR管,质保够长才放心。 +2. 电路不用全拆全改,厨卫空调用4平方线,其余用2.5平方线,选国标铜线。 +3. 厨卫水电必走顶,漏水易发现好维修,其他地方走地省材料。 +4. 验收必做水管打压30分钟无渗漏,电路测通断再签字。 +水电是隐蔽工程,紧盯施工别偷懒,别等返工才追悔莫及! +近期准备装修的可以找我领装修避坑手册,评论区回复避坑,直接拿走。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近水电主题,优先选水管错位、工地恶搞、水电完工环视等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选水路施工、电路施工、水电验收等贴合水电主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数。 +type 为 segment = 人物出镜;type=empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离 170–210(含数字,不含标点符号)、总时长偏离 42.5–52.5 秒。 +禁止篡改原文水电施工避坑相关的管材、线径、打压时长等核心细节和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “贴砖恶搞 - 恶搞开篇”, +“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, +“duration”: “5.25s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “瓷砖铺贴 - 瓷砖铺贴”, +“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, +“duration”: “5.00s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/油工进场要点——油工进场要交代的6句话.txt b/python-api/app/ai/prompts/system/bk/油工进场要点——油工进场要交代的6句话.txt index 81270b9..a21092f 100644 --- a/python-api/app/ai/prompts/system/bk/油工进场要点——油工进场要交代的6句话.txt +++ b/python-api/app/ai/prompts/system/bk/油工进场要点——油工进场要交代的6句话.txt @@ -1,258 +1,258 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:即将油工进场施工、不懂和油工师傅沟通话术,担心施工偷工减料、甲醛超标、墙面后期开裂掉皮的业主,严格围绕油工进场施工沟通避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 6 个油工施工沟通避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:以 “新房装修【核心场景:油工进场】,很多业主不懂行任由师傅自由施工,你以为他是帮你【表面好处:省事、按常规做法施工】,其实他就是图【错误目的:偷工减料、敷衍了事】。下面这 6 句话一定要记牢,照着跟师傅说不踩坑!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(6 个油工进场沟通要点,文案适当精简微调,意思保持原意,按原文序号排列,不随机抽取): -墙固涂刷:跟师傅交代原始墙面涂刷高渗透墙固,工费自理,有效预防墙面开裂反碱。 -挂网范围:不用全屋整体挂网,只在新老墙体交接、石膏板接缝位置局部挂网即可。 -腻子配比:腻子里面只能加水,禁止添加其他胶水,规避甲醛超标,守护家人健康。 -墙面找平:门口、踢脚线、衣柜周边重点做墙面找平,避免后期留出难看缝隙。 -吊顶防锈:吊顶所有钉子眼,必须人工涂刷防锈漆,防止后期生锈泛黄影响颜值。 -验收付款:油工全部施工完毕,验收合格之后再结尾款,严把施工质量关。 -(备注:保留原文 6 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,精简句式,控制整体纯文字 + 数字字数在 180-220 字,贴合短时长口播语感) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修流程避坑手册】,回复【核心关键词:避坑】直接拿走!” -【开篇 & 语言要求】 -开篇钩子,直击油工施工不懂沟通、容易被糊弄、墙面留隐患、甲醛超标的痛点,3 秒抓眼球,不拖沓不铺垫。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调精简句式,不得篡改原文油工施工沟通的核心细节和避坑逻辑,每句必须带标点断句。 -【内置固定原文案】 -油工进场不想踩坑,这 6 句话一定要跟师傅说,听完就懂行! -第一、跟师傅说原始墙刷高渗透墙固,工费我出,防开裂反碱。 -第二、不要全屋挂网,只在新老墙体、石膏板接缝处挂网就够。 -第三、腻子里除了水啥也不加,家里有老人小孩怕甲醛超标。 -第四、门口、踢脚线、衣柜周围重点找平,别留难看缝隙。 -第五、吊顶钉子眼一定要人工刷防锈漆,防止后期生锈难看。 -第六、油工验收合格再给钱,面子工程必须把好质量关。 -准备装修的朋友,评论区回复避坑直接领取装修流程避坑手册!直接拿着对照参考,少踩坑! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近油工主题,优先选墙面开裂、墙面空鼓、搞笑涂料施工等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙面基层、面漆涂刷、吊顶造型等贴合油工主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数。 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment” 对应 “人物出镜”,人物出镜画面内容可语句顺延到下一画面。 -“empty_shot” 对应上述素材库标题,文案内容需匹配,匹配不上选近似空镜。 -禁止总字数偏离 180–220(含数字,不含标点符号)、总时长偏离 45–55 秒。 -禁止篡改原文油工施工沟通避坑相关的核心细节和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment” 或 “empty_shot” -scene: “人物出镜” 或上述素材库标题 -voiceover: “配音文案” -duration: “分镜时长” -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "搞笑涂料施工 - 恶搞开篇", -"voiceover": "油工进场不想踩坑,记住这 6 句话就够了", -"duration": "4.25s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "照着这 6 点跟油工师傅沟通,再也不怕被糊弄", -"duration": "4.75s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "墙面基层 - 墙面基层", -"voiceover": "第一,原始墙面刷高渗透墙固,自费也能防开裂反碱。", -"duration": "5.25s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:即将油工进场施工、不懂和油工师傅沟通话术,担心施工偷工减料、甲醛超标、墙面后期开裂掉皮的业主,严格围绕油工进场施工沟通避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 6 个油工施工沟通避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:以 “新房装修【核心场景:油工进场】,很多业主不懂行任由师傅自由施工,你以为他是帮你【表面好处:省事、按常规做法施工】,其实他就是图【错误目的:偷工减料、敷衍了事】。下面这 6 句话一定要记牢,照着跟师傅说不踩坑!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(6 个油工进场沟通要点,文案适当精简微调,意思保持原意,按原文序号排列,不随机抽取): +墙固涂刷:跟师傅交代原始墙面涂刷高渗透墙固,工费自理,有效预防墙面开裂反碱。 +挂网范围:不用全屋整体挂网,只在新老墙体交接、石膏板接缝位置局部挂网即可。 +腻子配比:腻子里面只能加水,禁止添加其他胶水,规避甲醛超标,守护家人健康。 +墙面找平:门口、踢脚线、衣柜周边重点做墙面找平,避免后期留出难看缝隙。 +吊顶防锈:吊顶所有钉子眼,必须人工涂刷防锈漆,防止后期生锈泛黄影响颜值。 +验收付款:油工全部施工完毕,验收合格之后再结尾款,严把施工质量关。 +(备注:保留原文 6 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,精简句式,控制整体纯文字 + 数字字数在 180-220 字,贴合短时长口播语感) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修流程避坑手册】,回复【核心关键词:避坑】直接拿走!” +【开篇 & 语言要求】 +开篇钩子,直击油工施工不懂沟通、容易被糊弄、墙面留隐患、甲醛超标的痛点,3 秒抓眼球,不拖沓不铺垫。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调精简句式,不得篡改原文油工施工沟通的核心细节和避坑逻辑,每句必须带标点断句。 +【内置固定原文案】 +油工进场不想踩坑,这 6 句话一定要跟师傅说,听完就懂行! +第一、跟师傅说原始墙刷高渗透墙固,工费我出,防开裂反碱。 +第二、不要全屋挂网,只在新老墙体、石膏板接缝处挂网就够。 +第三、腻子里除了水啥也不加,家里有老人小孩怕甲醛超标。 +第四、门口、踢脚线、衣柜周围重点找平,别留难看缝隙。 +第五、吊顶钉子眼一定要人工刷防锈漆,防止后期生锈难看。 +第六、油工验收合格再给钱,面子工程必须把好质量关。 +准备装修的朋友,评论区回复避坑直接领取装修流程避坑手册!直接拿着对照参考,少踩坑! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近油工主题,优先选墙面开裂、墙面空鼓、搞笑涂料施工等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙面基层、面漆涂刷、吊顶造型等贴合油工主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数。 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment” 对应 “人物出镜”,人物出镜画面内容可语句顺延到下一画面。 +“empty_shot” 对应上述素材库标题,文案内容需匹配,匹配不上选近似空镜。 +禁止总字数偏离 180–220(含数字,不含标点符号)、总时长偏离 45–55 秒。 +禁止篡改原文油工施工沟通避坑相关的核心细节和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment” 或 “empty_shot” +scene: “人物出镜” 或上述素材库标题 +voiceover: “配音文案” +duration: “分镜时长” +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "搞笑涂料施工 - 恶搞开篇", +"voiceover": "油工进场不想踩坑,记住这 6 句话就够了", +"duration": "4.25s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "照着这 6 点跟油工师傅沟通,再也不怕被糊弄", +"duration": "4.75s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "墙面基层 - 墙面基层", +"voiceover": "第一,原始墙面刷高渗透墙固,自费也能防开裂反碱。", +"duration": "5.25s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/瓦工监工要点——瓦工进场监工记得交代的10件事.txt b/python-api/app/ai/prompts/system/bk/瓦工监工要点——瓦工进场监工记得交代的10件事.txt index 9a6b347..aa683aa 100644 --- a/python-api/app/ai/prompts/system/bk/瓦工监工要点——瓦工进场监工记得交代的10件事.txt +++ b/python-api/app/ai/prompts/system/bk/瓦工监工要点——瓦工进场监工记得交代的10件事.txt @@ -1,269 +1,269 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:新房装修瓦工进场、不懂专业监工、只会送礼讨好师傅、想靠专业话术把控施工细节的装修业主,围绕瓦工施工 10 句必备监工话术创作,每次生成随机打乱 10 条话术顺序重新编排,保留原意不变。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点引入 + 随机打乱 10 条瓦工监工话术 + 结尾福利引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,用接地气吐槽语气点出业主无效监工痛点,引出下文 10 句监工话术。 -中间核心(瓦工施工 10 句监工重点话术,文案可适当微调句式、口语化优化,保留每条原意不变,每次生成自动随机打乱重新编排顺序): -入户瓷砖优先铺整块,全屋通铺,边角料藏在家具遮挡位置。 -有色差、破损瑕疵瓷砖不要铺贴,单独放置留作商家退换。 -卫生间地面做好排水坡度,地漏做最低点,管道铺贴无断层。 -卫生间下水管道先贴阻尼片、包隔音棉,再砌砖贴砖做好隔音。 -后期装铝合金踢脚线,提前把控墙面与瓷砖预留缝隙大小。 -卫生间做单包套,四周必须完整贴砖,避免后期额外增项花钱。 -墙面出水口做好密封处理,从源头杜绝后期墙面渗水隐患。 -瓷砖转角统一做海棠角,预留美缝空间,禁止加装阳角条。 -止逆阀位置铺贴整块瓷砖,按尺寸精准开孔并顺手安装到位。 -橱柜、浴室柜不装挡水条,严控墙面阴阳角垂直度标准。 -(备注:完整保留原文 10 条监工话术核心细节、施工要求不变,仅微调口语适配口播;每次生成随机打乱 10 条顺序,不固定排序,始终保留每条原意,不篡改施工工艺和细节要求) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:内置 10 条瓦工监工固定要点,每次生成脚本自动随机打乱重新排序,不按原文固定顺序,避免内容重复同质化,适配短视频日更需求。 -文案调整要求:仅做口语化句式微调,把书面表述改成接地气口播大白话,不改动任何施工细节、工艺要求、禁忌标准,完整保留 10 条话术核心原意。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 440-480 字,按每秒 4 个纯文字计算,对应时长 110-120s,讲解饱满不拖沓,符合短视频用户完播习惯。 -内容适配性:打乱顺序后文案衔接自然,每条话术独立成点、逻辑通顺,贴合业主瓦工进场监工刚需,直击无效送礼不如专业话术管用的核心痛点,每一条都明确施工标准和避坑要点。 -结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领资料、评论区回复关键词、福利引导的核心逻辑。 -【开篇 & 语言要求】 -开篇完整沿用原文开头句式和吐槽语气,3 秒抓眼球,直击业主花钱送礼无效监工的通病,引出专业监工话术。 -全程口语化大白话,接地气、通俗易懂,站装修业主视角共情讲解,不生硬说教。 -可微调句式语序,严禁篡改 10 条瓦工监工话术的施工细节、工艺标准、硬性要求,每句带标点规范断句,适配口播节奏,不拆改核心语义。 -【内置固定原文案】 -我发现 90% 的业主都在无效监工,又是买水又是买烟又是送吃的。妄想用真情来打动师傅,我只能说你太天真了。要想装修不踩坑,真不如交代这十句话管用。 -第一句,师傅,我想要入户进门就看到整块砖,然后全屋通铺,把边角料全塞在家具能挡住的地方。 -第二句,铺贴时遇到有色差、破损的砖请别往上贴,单独放一边。我要找商家退换处理。 -第三句,卫生间地面我要做坡度,确保地漏是最低点,这样下水才快。另外,地漏不能有断层。 -第四句,师傅,卫生间的下水管道先贴阻尼片再包隔音棉,然后再砌砖包管子,最后贴瓷砖。 -第五句,师傅,后期我要装铝合金踢脚线,墙和瓷砖的缝隙别留太大。 -第六句,师傅,我家卫生间要做单包套,一定要记得给我四周贴砖,不然后期做门又得多花钱。 -第七句,师傅出水口一定要帮我做下密封处理,省得以后渗水。 -第八句,师傅,所有的转角都要海棠角,后期我要做美缝,千万别给我做阳角条。 -第九句,师傅需要贴止逆阀的地方一定要帮我贴一块整砖。我的止逆阀也买回来,你按这个开孔以后,顺手帮我装上吧。 -第十句,师傅,我家橱柜和浴室柜不打算装挡水条,所以对墙面阴阳角的垂直度要求比较高,麻烦你上点心啊。 -准备新房装修的朋友,我整理了装修全流程避坑手册。评论区回复避坑,拿去用。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓦工铺贴、监工话术主题,优先选贴砖恶搞、瓷砖铺贴、墙面空鼓等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、瓷砖开孔、墙面基层、水电验收等贴合瓦工监工主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "防水翻车漏水", -"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "卫生间基层清理 - 防水施工", -"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", -"duration": "5.50s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:新房装修瓦工进场、不懂专业监工、只会送礼讨好师傅、想靠专业话术把控施工细节的装修业主,围绕瓦工施工 10 句必备监工话术创作,每次生成随机打乱 10 条话术顺序重新编排,保留原意不变。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点引入 + 随机打乱 10 条瓦工监工话术 + 结尾福利引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,用接地气吐槽语气点出业主无效监工痛点,引出下文 10 句监工话术。 +中间核心(瓦工施工 10 句监工重点话术,文案可适当微调句式、口语化优化,保留每条原意不变,每次生成自动随机打乱重新编排顺序): +入户瓷砖优先铺整块,全屋通铺,边角料藏在家具遮挡位置。 +有色差、破损瑕疵瓷砖不要铺贴,单独放置留作商家退换。 +卫生间地面做好排水坡度,地漏做最低点,管道铺贴无断层。 +卫生间下水管道先贴阻尼片、包隔音棉,再砌砖贴砖做好隔音。 +后期装铝合金踢脚线,提前把控墙面与瓷砖预留缝隙大小。 +卫生间做单包套,四周必须完整贴砖,避免后期额外增项花钱。 +墙面出水口做好密封处理,从源头杜绝后期墙面渗水隐患。 +瓷砖转角统一做海棠角,预留美缝空间,禁止加装阳角条。 +止逆阀位置铺贴整块瓷砖,按尺寸精准开孔并顺手安装到位。 +橱柜、浴室柜不装挡水条,严控墙面阴阳角垂直度标准。 +(备注:完整保留原文 10 条监工话术核心细节、施工要求不变,仅微调口语适配口播;每次生成随机打乱 10 条顺序,不固定排序,始终保留每条原意,不篡改施工工艺和细节要求) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:内置 10 条瓦工监工固定要点,每次生成脚本自动随机打乱重新排序,不按原文固定顺序,避免内容重复同质化,适配短视频日更需求。 +文案调整要求:仅做口语化句式微调,把书面表述改成接地气口播大白话,不改动任何施工细节、工艺要求、禁忌标准,完整保留 10 条话术核心原意。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 440-480 字,按每秒 4 个纯文字计算,对应时长 110-120s,讲解饱满不拖沓,符合短视频用户完播习惯。 +内容适配性:打乱顺序后文案衔接自然,每条话术独立成点、逻辑通顺,贴合业主瓦工进场监工刚需,直击无效送礼不如专业话术管用的核心痛点,每一条都明确施工标准和避坑要点。 +结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领资料、评论区回复关键词、福利引导的核心逻辑。 +【开篇 & 语言要求】 +开篇完整沿用原文开头句式和吐槽语气,3 秒抓眼球,直击业主花钱送礼无效监工的通病,引出专业监工话术。 +全程口语化大白话,接地气、通俗易懂,站装修业主视角共情讲解,不生硬说教。 +可微调句式语序,严禁篡改 10 条瓦工监工话术的施工细节、工艺标准、硬性要求,每句带标点规范断句,适配口播节奏,不拆改核心语义。 +【内置固定原文案】 +我发现 90% 的业主都在无效监工,又是买水又是买烟又是送吃的。妄想用真情来打动师傅,我只能说你太天真了。要想装修不踩坑,真不如交代这十句话管用。 +第一句,师傅,我想要入户进门就看到整块砖,然后全屋通铺,把边角料全塞在家具能挡住的地方。 +第二句,铺贴时遇到有色差、破损的砖请别往上贴,单独放一边。我要找商家退换处理。 +第三句,卫生间地面我要做坡度,确保地漏是最低点,这样下水才快。另外,地漏不能有断层。 +第四句,师傅,卫生间的下水管道先贴阻尼片再包隔音棉,然后再砌砖包管子,最后贴瓷砖。 +第五句,师傅,后期我要装铝合金踢脚线,墙和瓷砖的缝隙别留太大。 +第六句,师傅,我家卫生间要做单包套,一定要记得给我四周贴砖,不然后期做门又得多花钱。 +第七句,师傅出水口一定要帮我做下密封处理,省得以后渗水。 +第八句,师傅,所有的转角都要海棠角,后期我要做美缝,千万别给我做阳角条。 +第九句,师傅需要贴止逆阀的地方一定要帮我贴一块整砖。我的止逆阀也买回来,你按这个开孔以后,顺手帮我装上吧。 +第十句,师傅,我家橱柜和浴室柜不打算装挡水条,所以对墙面阴阳角的垂直度要求比较高,麻烦你上点心啊。 +准备新房装修的朋友,我整理了装修全流程避坑手册。评论区回复避坑,拿去用。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓦工铺贴、监工话术主题,优先选贴砖恶搞、瓷砖铺贴、墙面空鼓等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、瓷砖开孔、墙面基层、水电验收等贴合瓦工监工主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "防水翻车漏水", +"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "卫生间基层清理 - 防水施工", +"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", +"duration": "5.50s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/瓦工避坑细节——瓦工避坑的7个细节.txt b/python-api/app/ai/prompts/system/bk/瓦工避坑细节——瓦工避坑的7个细节.txt index 02c71a9..d098824 100644 --- a/python-api/app/ai/prompts/system/bk/瓦工避坑细节——瓦工避坑的7个细节.txt +++ b/python-api/app/ai/prompts/system/bk/瓦工避坑细节——瓦工避坑的7个细节.txt @@ -1,260 +1,260 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:即将迎来瓦工进场、担心瓦工施工糊弄、后期瓷砖出现空鼓、开裂、脱落等问题的业主,严格围绕瓦工进场施工避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 7个瓦工施工避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏9:16拍摄 -【核心强制规则】 -开头范式:以“新房装修【核心场景:瓦工进场】,谁要是满脑子只想着【错误操作:做海棠角、全屋通铺墙壁对缝】,你就直接【拒绝动作:别只盯着这些】。你以为他是帮你【表面好处:做美观、显工艺】,其实他就是图【错误目的:糊弄你、省事儿】。下面这7个细节一定要看仔细,少看一条都可能亏几万!”为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(7个瓦工进场避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): -1. 瓷砖排版:瓷砖排版别让瓦工来做,买砖的时候让商家设计师免费给你排好版。瓦工手艺再好,也比不过电脑精准,进场时让师傅拿着图纸现场复核一遍,没问题再施工。 -2. 瓷砖筛选:交代师傅有色差和瑕疵的砖不能贴,一定要挑出来找商家换货,还要检查瓷砖背面有没有脱墨剂,这玩意儿会严重降低瓷砖粘性,导致瓷砖脱落,必须清理干净才能贴。 -3. 贴砖方向:贴砖时让师傅按砖背面的箭头方向来贴,不然贴完瓷砖表面光泽不一致,一块深一块浅,丑得没法看,后期想改都要砸砖返工。 -4. 抗裂处理:新旧墙体交接处、烟道位置,记得让师傅挂钢丝网,抹上抗裂砂浆再贴砖,不然季节交替热胀冷缩,这里的砖很容易空鼓、脱落。 -5. 瓷砖开孔:所有需要开孔的瓷砖,必须用专业开孔器来开,保证开孔规整,不然后期瓷砖很容易从开口处开裂,影响美观还存在安全隐患。 -6. 卫生间回填:卫生间千万不要用建筑垃圾回填,让师傅用陶粒回填,陶粒质轻还吸水,回填完再铺一层钢筋网,加水泥找平,才能保证后期地面不下沉。 -7. 后期保护:师傅贴完砖以后要及时清缝,后期美缝才不会崩瓷,还要用厚纸板把地砖盖好,做好成品保护,避免后期施工造成刮痕。 -(备注:保留原文7个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当调整句式让口语化更贴合口播) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑手续】,回复【核心关键词:避坑】直接拿走!” -【开篇&语言要求】 -开篇钩子,直击瓦工施工糊弄、后期瓷砖出问题的痛点,3秒抓眼球,不拖沓不铺垫。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调句式,不得篡改原文中瓦工施工的核心细节和避坑逻辑,每句必须带标点断句。 -【内置固定原文案】 -瓦工进场,如果你满脑子只有做海棠角,全屋通铺墙壁对缝,那你后面肯定要踩大坑。瓦工一来,你先交代好这7个细节,师傅听了就不敢糊弄你。 -第一,瓷砖不需要瓦工排版,买砖的时候让商家设计师免费给你排好版。瓦工手艺再好,也比不过电脑精准。进场时,让师傅拿着图纸现场复核一遍,没问题再施工。 -第二,交代师傅有色差和瑕疵的砖不能贴,一定要挑出来找商家换货,还要检查瓷砖背面有没有脱墨剂。这玩意儿会严重降低瓷砖的粘性,导致瓷砖往下掉。必须清理干净才能贴。 -第三,贴砖的时候,让师傅按砖背面的箭头方向来贴,不然贴完表面光泽不一样,一块儿深一块儿浅,丑的没法看。 -第四,新旧墙体交接处、烟道位置记得让师傅挂钢丝网,抹上抗裂砂浆再贴砖,不然季节交替,热胀冷缩,这里的砖很容易空鼓脱落。 -第五,所有需要开孔的瓷砖必须用专业开孔器来开,保证开孔规整,不然后期瓷砖很容易从开口处开裂。 -第六,卫生间千万不要用建筑垃圾回填,让师傅用陶粒回填,陶粒轻还吸水。回填完再铺一层钢筋网,加水泥找平,才能保证后期地面不下沉。 -第七,师傅贴完砖以后要及时清缝,后期美缝才不会崩瓷,还要用厚纸板把地砖盖好,做好保护,避免后期施工造成刮痕。 -准备新房装修的朋友,我整理了一份装修全流程避坑手续。回复避坑,直接拿去用。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓦工主题,优先选贴砖恶搞、墙面空鼓、瓷砖开裂等相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、瓷砖开孔、陶粒回填等贴合瓦工主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" -type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离400–480(含数字,不含标点符号)、总时长偏离100–120秒。 -禁止篡改原文瓦工避坑相关的核心细节和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “贴砖恶搞 - 恶搞开篇”, -“voiceover”: “瓦工进场只盯海棠角、通缝,后期必踩大坑”, -“duration”: “4.25s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “先交代这7个细节,师傅绝对不敢糊弄你”, -“duration”: “4.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “瓷砖铺贴 - 瓷砖铺贴”, -“voiceover”: “第一,瓷砖排版别让瓦工做,商家设计师免费排更精准。”, -“duration”: “5.50s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:即将迎来瓦工进场、担心瓦工施工糊弄、后期瓷砖出现空鼓、开裂、脱落等问题的业主,严格围绕瓦工进场施工避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 7个瓦工施工避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏9:16拍摄 +【核心强制规则】 +开头范式:以“新房装修【核心场景:瓦工进场】,谁要是满脑子只想着【错误操作:做海棠角、全屋通铺墙壁对缝】,你就直接【拒绝动作:别只盯着这些】。你以为他是帮你【表面好处:做美观、显工艺】,其实他就是图【错误目的:糊弄你、省事儿】。下面这7个细节一定要看仔细,少看一条都可能亏几万!”为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(7个瓦工进场避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): +1. 瓷砖排版:瓷砖排版别让瓦工来做,买砖的时候让商家设计师免费给你排好版。瓦工手艺再好,也比不过电脑精准,进场时让师傅拿着图纸现场复核一遍,没问题再施工。 +2. 瓷砖筛选:交代师傅有色差和瑕疵的砖不能贴,一定要挑出来找商家换货,还要检查瓷砖背面有没有脱墨剂,这玩意儿会严重降低瓷砖粘性,导致瓷砖脱落,必须清理干净才能贴。 +3. 贴砖方向:贴砖时让师傅按砖背面的箭头方向来贴,不然贴完瓷砖表面光泽不一致,一块深一块浅,丑得没法看,后期想改都要砸砖返工。 +4. 抗裂处理:新旧墙体交接处、烟道位置,记得让师傅挂钢丝网,抹上抗裂砂浆再贴砖,不然季节交替热胀冷缩,这里的砖很容易空鼓、脱落。 +5. 瓷砖开孔:所有需要开孔的瓷砖,必须用专业开孔器来开,保证开孔规整,不然后期瓷砖很容易从开口处开裂,影响美观还存在安全隐患。 +6. 卫生间回填:卫生间千万不要用建筑垃圾回填,让师傅用陶粒回填,陶粒质轻还吸水,回填完再铺一层钢筋网,加水泥找平,才能保证后期地面不下沉。 +7. 后期保护:师傅贴完砖以后要及时清缝,后期美缝才不会崩瓷,还要用厚纸板把地砖盖好,做好成品保护,避免后期施工造成刮痕。 +(备注:保留原文7个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当调整句式让口语化更贴合口播) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑手续】,回复【核心关键词:避坑】直接拿走!” +【开篇&语言要求】 +开篇钩子,直击瓦工施工糊弄、后期瓷砖出问题的痛点,3秒抓眼球,不拖沓不铺垫。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调句式,不得篡改原文中瓦工施工的核心细节和避坑逻辑,每句必须带标点断句。 +【内置固定原文案】 +瓦工进场,如果你满脑子只有做海棠角,全屋通铺墙壁对缝,那你后面肯定要踩大坑。瓦工一来,你先交代好这7个细节,师傅听了就不敢糊弄你。 +第一,瓷砖不需要瓦工排版,买砖的时候让商家设计师免费给你排好版。瓦工手艺再好,也比不过电脑精准。进场时,让师傅拿着图纸现场复核一遍,没问题再施工。 +第二,交代师傅有色差和瑕疵的砖不能贴,一定要挑出来找商家换货,还要检查瓷砖背面有没有脱墨剂。这玩意儿会严重降低瓷砖的粘性,导致瓷砖往下掉。必须清理干净才能贴。 +第三,贴砖的时候,让师傅按砖背面的箭头方向来贴,不然贴完表面光泽不一样,一块儿深一块儿浅,丑的没法看。 +第四,新旧墙体交接处、烟道位置记得让师傅挂钢丝网,抹上抗裂砂浆再贴砖,不然季节交替,热胀冷缩,这里的砖很容易空鼓脱落。 +第五,所有需要开孔的瓷砖必须用专业开孔器来开,保证开孔规整,不然后期瓷砖很容易从开口处开裂。 +第六,卫生间千万不要用建筑垃圾回填,让师傅用陶粒回填,陶粒轻还吸水。回填完再铺一层钢筋网,加水泥找平,才能保证后期地面不下沉。 +第七,师傅贴完砖以后要及时清缝,后期美缝才不会崩瓷,还要用厚纸板把地砖盖好,做好保护,避免后期施工造成刮痕。 +准备新房装修的朋友,我整理了一份装修全流程避坑手续。回复避坑,直接拿去用。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓦工主题,优先选贴砖恶搞、墙面空鼓、瓷砖开裂等相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、瓷砖开孔、陶粒回填等贴合瓦工主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" +type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离400–480(含数字,不含标点符号)、总时长偏离100–120秒。 +禁止篡改原文瓦工避坑相关的核心细节和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “贴砖恶搞 - 恶搞开篇”, +“voiceover”: “瓦工进场只盯海棠角、通缝,后期必踩大坑”, +“duration”: “4.25s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “先交代这7个细节,师傅绝对不敢糊弄你”, +“duration”: “4.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “瓷砖铺贴 - 瓷砖铺贴”, +“voiceover”: “第一,瓷砖排版别让瓦工做,商家设计师免费排更精准。”, +“duration”: “5.50s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/瓦工铺贴停工——瓷砖铺完不要着急干的5件事.txt b/python-api/app/ai/prompts/system/bk/瓦工铺贴停工——瓷砖铺完不要着急干的5件事.txt index a5f3f59..bad4fd5 100644 --- a/python-api/app/ai/prompts/system/bk/瓦工铺贴停工——瓷砖铺完不要着急干的5件事.txt +++ b/python-api/app/ai/prompts/system/bk/瓦工铺贴停工——瓷砖铺完不要着急干的5件事.txt @@ -1,259 +1,259 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:瓷砖刚铺贴完成、被装修公司催促赶工期、不懂停工注意事项、容易提前施工留下后期隐患的装修业主,围绕瓷砖铺贴后5件必停必等事项创作,按原文序号排列,不随机抽取。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 5个瓷砖铺贴停工避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏9:16拍摄 -【核心强制规则】 -开头范式:以“瓷砖铺完后必须要停工几天,哪怕是装修公司催,下面这5件事也别着急着干,不然后期出问题,责任全是你自己的。”为核心句式,用警示性语气点出常见坑,引出下文5个要点(保留原文开头核心原意,适配范式结构)。 -中间核心(5个瓷砖铺贴停工避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): -1. 瓦工验收:瓦工结束后不能立马验收。装修公司这时候拿个空鼓锤来,就是忽悠你不懂。你要是签字了,后期有问题就是你的责任了。这里一定要等水泥砂浆干透了,才能验出来是否空鼓,最起码要等五六天左右。 -2. 美缝施工:美缝不能在瓷砖刚铺完就做,要等一周左右,等缝隙里面的水迹干透了,检查有没有空鼓了再做美缝。不然后期出现了反碱脱落,后续维权麻烦不说,还得返工耗费时间金钱。 -3. 瓷砖养护:瓷砖铺完后千万不要洒水,你洒水养护的是下面的水泥砂浆,那活儿,瓦工铺的时候就应该把墙面地面打湿再贴,铺完了再打扫干净,盖好保护膜就可以了,别多此一举。 -4. 标识保留:墙面的水电标识贴不要撕,这是给后期安装师傅看的。你一撕,人家打孔打到水管电线,不仅维修麻烦,还可能造成安全隐患,得不偿失。 -5. 停工利用:停工这几天也别闲着。闲着你就可以让定制商家上门复尺,提前下单,定制周期差不多一个月,到时候你家油工结束了,这些东西正好能装,一点儿不耽误工期。 -(备注:保留原文5个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当调整句式让口语化更贴合口播,补充美缝反碱、水电标识撕毁的危害,贴合搜索参考内容) -### 中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -1. 排序逻辑:严格按原文5个要点的序号排列,不随机抽取、不打乱顺序,保证内容连贯性,贴合业主瓷砖铺贴后停工的实际流程,从验收、施工、养护、标识到工期利用,层层递进,符合业主认知逻辑。 -2. 文案调整要求:微调仅针对句式口语化优化,比如将书面化表述改为抖音/视频号口播常用的接地气语气,补充轻微危害提示(结合美缝反碱脱落、水电标识撕毁的隐患),不改变每个坑的核心信息——如验收等待五六天、美缝等待一周、禁止洒水、保留水电标识、定制复尺周期一个月等核心时间节点和禁忌,所有细节完全保留,贴合原文原意。 -3. 字数与时长控制:纯文字+数字(扣除标点)严格控制在400-480字,按每秒4个纯文字计算,对应时长100-120s,既保证每个避坑点讲解透彻,补充必要危害提示,又不拖沓,符合短视频用户观看习惯,避免用户划走。 -4. 内容适配性:5个避坑要点讲解时需衔接自然,每个坑独立成段(分镜对应空镜),不重复、不冗余,重点突出“停工避坑”核心,贴合业主担心被装修公司催促、怕后期出问题自己担责、想合理利用停工时间的核心痛点,每段讲解都紧扣“为什么不能做、怎么做才对”的逻辑,与原文保持一致,结合参考内容完善危害提示,增强说服力。 -结尾范式:以“如果你们也在准备新房装修,不知道还有哪些坑要避,评论区回复 ‘装修’,我把整理好的装修避坑手册,免费发给你们,帮你们省时间、省钱!记得关注我,装修不踩坑!”为核心句式,保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动领福利、评论区回复关键词、关注引导的核心逻辑。 -【开篇&语言要求】 -开篇严格遵循核心强制规则的警示性句式,3秒抓眼球不拖沓,用犀利语气点出瓷砖铺贴后被催工期、盲目施工后期担责的痛点,贴合装修业主避坑需求,不偏离范式结构。 -全程口语化大白话,小白易懂、不生硬说教,站业主共情立场,用警示性语气讲解,贴合口播传播特点,增强代入感,补充的危害提示通俗易懂,让业主清晰了解违规操作的后果。 -可微调句式语序,严禁篡改5个停工避坑要点的核心细节、时间节点、操作规范,每句带标点规范断句,适配口播节奏,避免大长句,同时结合参考内容完善美缝反碱、水电标识相关危害表述。 -【内置固定原文案】 -瓷砖铺完后必须要停工几天,哪怕是装修公司催,下面这5件事也别着急着干,不然后期出问题,责任全是你自己的。 -第一,瓦工结束后不能立马验收。装修公司这时候拿个空鼓锤来,就是忽悠你不懂。你要是签字了,后期有问题就是你的责任了。这里呢,是一定要等水泥砂浆干透了,才能验出来是否空鼓,最起码要等五六天左右。 -第二,美缝不能在瓷砖刚铺完就做,要等一周左右,等缝隙里面的水迹干透了,检查有没有空鼓了再做美缝。不然后期出现了反碱脱落,你找谁去?毕竟美缝反碱后会形成隔离层,导致粘结不牢固,返工又费钱又费力。 -第三,瓷砖铺完后千万不要洒水,你洒水养护的是下面的水泥砂浆,那活儿,瓦工铺的时候就应该把墙面地面打湿再贴,铺完了再打扫干净,盖好保护膜就可以了,别多此一举。 -第四,墙面的水电标识贴不要撕,这是给后期安装师傅看的。你一撕,人家打孔打到水管电线,你就等着哭吧,不仅维修麻烦,还可能引发安全隐患。 -最后,停工这几天也别闲着。闲着你就可以让定制商家上门复尺,提前下单,定制周期差不多一个月,到时候你家油工结束了,这些东西正好能装,一点儿不耽误工期。 -如果你们也在准备新房装修,不知道还有哪些坑要避,评论区回复 “装修”,我把整理好的装修避坑手册,免费发给你们,帮你们省时间、省钱!记得关注我,装修不踩坑! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓷砖铺贴、停工避坑主题,优先选贴砖恶搞、墙面空鼓、瓷砖铺贴等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、美缝施工、成品保护、水电验收等贴合瓷砖铺贴停工主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓦工结束后不能立马验收,至少要等五六天。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “瓷砖铺完别着急复工,这 5 件事做早了全是坑” 总共 20 个文字 1 个数字,则是 "5.25s" -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “瓷砖铺完别着急复工,这 5 件事做早了全是坑” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "贴砖恶搞 - 恶搞开篇", -"voiceover": "瓷砖铺完别着急复工,装修公司催也别理,5 件事必等!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "这些事做早了后期全是坑,责任还得你自己担!", -"duration": "5.00s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "瓷砖铺贴 - 瓷砖完工展示", -"voiceover": "第一,瓦工结束别立马验收,至少等五六天再验空鼓!", -"duration": "5.50s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:瓷砖刚铺贴完成、被装修公司催促赶工期、不懂停工注意事项、容易提前施工留下后期隐患的装修业主,围绕瓷砖铺贴后5件必停必等事项创作,按原文序号排列,不随机抽取。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 5个瓷砖铺贴停工避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏9:16拍摄 +【核心强制规则】 +开头范式:以“瓷砖铺完后必须要停工几天,哪怕是装修公司催,下面这5件事也别着急着干,不然后期出问题,责任全是你自己的。”为核心句式,用警示性语气点出常见坑,引出下文5个要点(保留原文开头核心原意,适配范式结构)。 +中间核心(5个瓷砖铺贴停工避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): +1. 瓦工验收:瓦工结束后不能立马验收。装修公司这时候拿个空鼓锤来,就是忽悠你不懂。你要是签字了,后期有问题就是你的责任了。这里一定要等水泥砂浆干透了,才能验出来是否空鼓,最起码要等五六天左右。 +2. 美缝施工:美缝不能在瓷砖刚铺完就做,要等一周左右,等缝隙里面的水迹干透了,检查有没有空鼓了再做美缝。不然后期出现了反碱脱落,后续维权麻烦不说,还得返工耗费时间金钱。 +3. 瓷砖养护:瓷砖铺完后千万不要洒水,你洒水养护的是下面的水泥砂浆,那活儿,瓦工铺的时候就应该把墙面地面打湿再贴,铺完了再打扫干净,盖好保护膜就可以了,别多此一举。 +4. 标识保留:墙面的水电标识贴不要撕,这是给后期安装师傅看的。你一撕,人家打孔打到水管电线,不仅维修麻烦,还可能造成安全隐患,得不偿失。 +5. 停工利用:停工这几天也别闲着。闲着你就可以让定制商家上门复尺,提前下单,定制周期差不多一个月,到时候你家油工结束了,这些东西正好能装,一点儿不耽误工期。 +(备注:保留原文5个要点,按原文序号排列,保留原文核心细节和避坑逻辑,适当调整句式让口语化更贴合口播,补充美缝反碱、水电标识撕毁的危害,贴合搜索参考内容) +### 中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +1. 排序逻辑:严格按原文5个要点的序号排列,不随机抽取、不打乱顺序,保证内容连贯性,贴合业主瓷砖铺贴后停工的实际流程,从验收、施工、养护、标识到工期利用,层层递进,符合业主认知逻辑。 +2. 文案调整要求:微调仅针对句式口语化优化,比如将书面化表述改为抖音/视频号口播常用的接地气语气,补充轻微危害提示(结合美缝反碱脱落、水电标识撕毁的隐患),不改变每个坑的核心信息——如验收等待五六天、美缝等待一周、禁止洒水、保留水电标识、定制复尺周期一个月等核心时间节点和禁忌,所有细节完全保留,贴合原文原意。 +3. 字数与时长控制:纯文字+数字(扣除标点)严格控制在400-480字,按每秒4个纯文字计算,对应时长100-120s,既保证每个避坑点讲解透彻,补充必要危害提示,又不拖沓,符合短视频用户观看习惯,避免用户划走。 +4. 内容适配性:5个避坑要点讲解时需衔接自然,每个坑独立成段(分镜对应空镜),不重复、不冗余,重点突出“停工避坑”核心,贴合业主担心被装修公司催促、怕后期出问题自己担责、想合理利用停工时间的核心痛点,每段讲解都紧扣“为什么不能做、怎么做才对”的逻辑,与原文保持一致,结合参考内容完善危害提示,增强说服力。 +结尾范式:以“如果你们也在准备新房装修,不知道还有哪些坑要避,评论区回复 ‘装修’,我把整理好的装修避坑手册,免费发给你们,帮你们省时间、省钱!记得关注我,装修不踩坑!”为核心句式,保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动领福利、评论区回复关键词、关注引导的核心逻辑。 +【开篇&语言要求】 +开篇严格遵循核心强制规则的警示性句式,3秒抓眼球不拖沓,用犀利语气点出瓷砖铺贴后被催工期、盲目施工后期担责的痛点,贴合装修业主避坑需求,不偏离范式结构。 +全程口语化大白话,小白易懂、不生硬说教,站业主共情立场,用警示性语气讲解,贴合口播传播特点,增强代入感,补充的危害提示通俗易懂,让业主清晰了解违规操作的后果。 +可微调句式语序,严禁篡改5个停工避坑要点的核心细节、时间节点、操作规范,每句带标点规范断句,适配口播节奏,避免大长句,同时结合参考内容完善美缝反碱、水电标识相关危害表述。 +【内置固定原文案】 +瓷砖铺完后必须要停工几天,哪怕是装修公司催,下面这5件事也别着急着干,不然后期出问题,责任全是你自己的。 +第一,瓦工结束后不能立马验收。装修公司这时候拿个空鼓锤来,就是忽悠你不懂。你要是签字了,后期有问题就是你的责任了。这里呢,是一定要等水泥砂浆干透了,才能验出来是否空鼓,最起码要等五六天左右。 +第二,美缝不能在瓷砖刚铺完就做,要等一周左右,等缝隙里面的水迹干透了,检查有没有空鼓了再做美缝。不然后期出现了反碱脱落,你找谁去?毕竟美缝反碱后会形成隔离层,导致粘结不牢固,返工又费钱又费力。 +第三,瓷砖铺完后千万不要洒水,你洒水养护的是下面的水泥砂浆,那活儿,瓦工铺的时候就应该把墙面地面打湿再贴,铺完了再打扫干净,盖好保护膜就可以了,别多此一举。 +第四,墙面的水电标识贴不要撕,这是给后期安装师傅看的。你一撕,人家打孔打到水管电线,你就等着哭吧,不仅维修麻烦,还可能引发安全隐患。 +最后,停工这几天也别闲着。闲着你就可以让定制商家上门复尺,提前下单,定制周期差不多一个月,到时候你家油工结束了,这些东西正好能装,一点儿不耽误工期。 +如果你们也在准备新房装修,不知道还有哪些坑要避,评论区回复 “装修”,我把整理好的装修避坑手册,免费发给你们,帮你们省时间、省钱!记得关注我,装修不踩坑! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近瓷砖铺贴、停工避坑主题,优先选贴砖恶搞、墙面空鼓、瓷砖铺贴等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选瓷砖铺贴、美缝施工、成品保护、水电验收等贴合瓷砖铺贴停工主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓦工结束后不能立马验收,至少要等五六天。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “瓷砖铺完别着急复工,这 5 件事做早了全是坑” 总共 20 个文字 1 个数字,则是 "5.25s" +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “瓷砖铺完别着急复工,这 5 件事做早了全是坑” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "贴砖恶搞 - 恶搞开篇", +"voiceover": "瓷砖铺完别着急复工,装修公司催也别理,5 件事必等!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "这些事做早了后期全是坑,责任还得你自己担!", +"duration": "5.00s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "瓷砖铺贴 - 瓷砖完工展示", +"voiceover": "第一,瓦工结束别立马验收,至少等五六天再验空鼓!", +"duration": "5.50s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/监工关键节点——装修必须在场的7个节点.txt b/python-api/app/ai/prompts/system/bk/监工关键节点——装修必须在场的7个节点.txt index 85d475e..aaa2c45 100644 --- a/python-api/app/ai/prompts/system/bk/监工关键节点——装修必须在场的7个节点.txt +++ b/python-api/app/ai/prompts/system/bk/监工关键节点——装修必须在场的7个节点.txt @@ -1,260 +1,260 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备新房装修、不清楚哪些施工节点必须在场监工,担心师傅偷工减料、后期入住变成甲醛房的业主,严格围绕装修 7 个必在场施工节点避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 7 个装修关键节点避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:以 “新房装修【核心场景:全流程施工】,很多业主全程不到场监工,只看重表面装修效果。你以为他是帮你【表面好处:省心、省时间】,其实他就是图【错误目的:偷工减料、糊弄业主】。下面这 7 个在场时间一定要记牢,尤其最后一个关乎是不是甲醛房!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(7 个装修必在场节点要点,文案适当精简调整,意思保持原意,按原文序号排列,不随机抽取): -砸墙施工:砸墙阶段务必在场,盯紧师傅封好下水口,避免管道堵塞,后期还要下楼疏通。 -窗户安装:封窗施工一定要到场,监督做好防水斜坡,杜绝雨天雨水往室内倒灌渗水。 -水电验收:水电完工验收必须在场,核对开关插座点位,包裹强弱电并拍照留存防返工。 -防水瓷砖:防水和瓷砖验收要在场,闭水试验排查漏水,核对瓷砖型号避免色差重铺。 -瓷砖铺贴:贴砖期间现场监督,检查瓷砖平整度、空鼓率,保证阴阳角方正、缝隙均匀。 -木工吊顶:木工做吊顶务必在场,拐角整板铺设、接缝开 V 型槽,防止后期乳胶漆开裂。 -腻子施工:刮腻子阶段一定要在场,禁止往腻子里加胶水,避免甲醛超标形成毒气房。 -(备注:保留原文 7 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,精简句式控制整体字数,贴合口播语感) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全程避坑手册】,回复【核心关键词:避坑】直接拿走!” -【开篇 & 语言要求】 -开篇钩子,直击装修不懂监工节点、容易被糊弄、住进甲醛房的痛点,3 秒抓眼球,不拖沓不铺垫。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调精简句式,不得篡改原文各施工节点核心监督细节和避坑逻辑,每句必须带标点断句。 -【内置固定原文案】 -新房装修一定要在场的 7 个时间,尤其最后一个,直接关系是不是甲醛房! -第一,砸墙时必须在场,盯紧师傅封好下水口,不然堵了还要跑楼下疏通。 -第二,封窗时一定要在场,监督做好防水斜坡,防止下雨天雨水往屋里倒灌。 -第三,水电验收必须在场,核对点位、查强弱电包裹,记得拍照留存避返工。 -第四,防水瓷砖验收必在场,闭水试验查漏水,核对瓷砖型号防色差重铺。 -第五,贴砖时要在场,检查平整度空鼓率,阴阳角方正、缝隙均匀才合格。 -第六,木工吊顶必在场,拐角整板、接缝做 V 型槽,杜绝后期乳胶漆开裂。 -第七,刮腻子一定要在场,严禁往腻子加胶水,不然甲醛超标变毒气房。 -准备装修的朋友,我整理了避坑手册,评论区回复避坑直接领取参考! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修监工主题,优先选工地恶搞、墙体拆除、墙面开裂等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙体拆除、吊顶造型、水电验收、瓷砖铺贴等贴合施工节点主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s" -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离 240–280(含数字,不含标点符号)、总时长偏离 60–70 秒。 -禁止篡改原文装修 7 大施工节点监工相关的核心细节和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “贴砖恶搞 - 恶搞开篇”, -“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, -“duration”: “5.50s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “瓷砖铺贴 - 瓷砖铺贴”, -“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, -“duration”: “5.00s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备新房装修、不清楚哪些施工节点必须在场监工,担心师傅偷工减料、后期入住变成甲醛房的业主,严格围绕装修 7 个必在场施工节点避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 7 个装修关键节点避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:以 “新房装修【核心场景:全流程施工】,很多业主全程不到场监工,只看重表面装修效果。你以为他是帮你【表面好处:省心、省时间】,其实他就是图【错误目的:偷工减料、糊弄业主】。下面这 7 个在场时间一定要记牢,尤其最后一个关乎是不是甲醛房!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(7 个装修必在场节点要点,文案适当精简调整,意思保持原意,按原文序号排列,不随机抽取): +砸墙施工:砸墙阶段务必在场,盯紧师傅封好下水口,避免管道堵塞,后期还要下楼疏通。 +窗户安装:封窗施工一定要到场,监督做好防水斜坡,杜绝雨天雨水往室内倒灌渗水。 +水电验收:水电完工验收必须在场,核对开关插座点位,包裹强弱电并拍照留存防返工。 +防水瓷砖:防水和瓷砖验收要在场,闭水试验排查漏水,核对瓷砖型号避免色差重铺。 +瓷砖铺贴:贴砖期间现场监督,检查瓷砖平整度、空鼓率,保证阴阳角方正、缝隙均匀。 +木工吊顶:木工做吊顶务必在场,拐角整板铺设、接缝开 V 型槽,防止后期乳胶漆开裂。 +腻子施工:刮腻子阶段一定要在场,禁止往腻子里加胶水,避免甲醛超标形成毒气房。 +(备注:保留原文 7 个要点,按原文序号排列,保留原文核心细节和避坑逻辑,精简句式控制整体字数,贴合口播语感) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全程避坑手册】,回复【核心关键词:避坑】直接拿走!” +【开篇 & 语言要求】 +开篇钩子,直击装修不懂监工节点、容易被糊弄、住进甲醛房的痛点,3 秒抓眼球,不拖沓不铺垫。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调精简句式,不得篡改原文各施工节点核心监督细节和避坑逻辑,每句必须带标点断句。 +【内置固定原文案】 +新房装修一定要在场的 7 个时间,尤其最后一个,直接关系是不是甲醛房! +第一,砸墙时必须在场,盯紧师傅封好下水口,不然堵了还要跑楼下疏通。 +第二,封窗时一定要在场,监督做好防水斜坡,防止下雨天雨水往屋里倒灌。 +第三,水电验收必须在场,核对点位、查强弱电包裹,记得拍照留存避返工。 +第四,防水瓷砖验收必在场,闭水试验查漏水,核对瓷砖型号防色差重铺。 +第五,贴砖时要在场,检查平整度空鼓率,阴阳角方正、缝隙均匀才合格。 +第六,木工吊顶必在场,拐角整板、接缝做 V 型槽,杜绝后期乳胶漆开裂。 +第七,刮腻子一定要在场,严禁往腻子加胶水,不然甲醛超标变毒气房。 +准备装修的朋友,我整理了避坑手册,评论区回复避坑直接领取参考! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修监工主题,优先选工地恶搞、墙体拆除、墙面开裂等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙体拆除、吊顶造型、水电验收、瓷砖铺贴等贴合施工节点主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓷砖排版别让瓦工来做,商家设计师免费排版更精准。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s" +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离 240–280(含数字,不含标点符号)、总时长偏离 60–70 秒。 +禁止篡改原文装修 7 大施工节点监工相关的核心细节和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “贴砖恶搞 - 恶搞开篇”, +“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, +“duration”: “5.50s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “瓷砖铺贴 - 瓷砖铺贴”, +“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, +“duration”: “5.00s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/硬装收尾要点——硬装结束前的收尾工作.txt b/python-api/app/ai/prompts/system/bk/硬装收尾要点——硬装结束前的收尾工作.txt index 09b5e06..48c1e76 100644 --- a/python-api/app/ai/prompts/system/bk/硬装收尾要点——硬装结束前的收尾工作.txt +++ b/python-api/app/ai/prompts/system/bk/硬装收尾要点——硬装结束前的收尾工作.txt @@ -1,177 +1,177 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:硬装刚完工、不懂软装进场前后收尾细节、着急搬家具入住容易遗留隐患,后期发霉反味、墙面破损难修补的装修业主,围绕硬装结束必做 7 个收尾关键要点创作,按原意逻辑编排,可适度口语微调保留原意。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头硬装收尾痛点引入 + 6 个收尾避坑干货 + 结尾避坑手册引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用警示现实视角点出硬装刚完工别急着进软装,忽略 7 个收尾细节入住容易留隐患、生活闹心吵架的痛点,引出下文 6 个必做收尾关键点。 -中间核心(硬装完工 6 个收尾避坑要点,文案适当调整修改,意思保持原意,保留原有先后逻辑,不随机打乱,可口语顺滑润色): -瓷砖除蜡:亮光砖、柔光砖在家具进场前,一定要用瓷砖除蜡剂全屋拖洗一遍,避免表层蜡质残留,入住后地面发蒙有水雾感,看着别扭难打理。 -柜体防护:餐边柜、橱柜吊柜底部贴静电防水膜,阻隔水汽熏坏柜体;橱柜内部铺贴铝箔纸,提升防潮效果,日常清洁打理更省心。 -地漏整改:逐一检查全屋地漏是否存在断层,有断层及时加装加长地漏芯,防止渗水进入砂浆层,避免后期反味、墙面起皮发霉等遗留隐患。 -全屋打胶:家具进场前提前做全屋精细打胶,重点处理踢脚线底部、厨卫窗框与瓷砖交接位置,优先用美容胶,不建议用美缝剂,避免材质过硬后期脱落开裂。 -止逆阀对接:检查油烟机、卫生间浴霸和排风扇,确认排风管与止逆阀规范连接,杜绝师傅偷懒随意摆放管路,防止后期全屋倒灌异味。 -原漆留存:乳胶漆完工后预留未兑水原装漆,密封保存备用,后期装门、装柜体出现磕碰掉漆,可随时修补还原,不用整体返工刷漆。 -(备注:保留原文 7 个收尾要点的核心细节、施工逻辑、隐患后果不变,适当调整句式让口语化更贴合口播,不篡改工艺做法、选材建议、遗留隐患的核心逻辑) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:严格按原文 6 大收尾要点顺序排列,不打乱结构,贴合硬装完工到软装进场的真实施工流程,层层递进符合业主装修收尾认知逻辑。 -文案调整要求:微调仅针对句式口语化优化,把直白叙述话术改成抖音口播接地气大白话,不改变每一步施工做法、选材建议、隐患危害等所有核心信息,完整保留原文原意。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 440-480 字,按每秒 4 个纯文字计算,对应时长 110-120s,讲解收尾细节细致不啰嗦,节奏适中,适配短视频完播率。 -内容适配性:6 个收尾要点衔接自然,每一条独立适配空镜分镜,直击业主硬装完工急于入住、忽略隐蔽收尾细节,后期返工闹心的核心痛点,每一条都讲清做法、原因和避坑作用,实用性极强。 -结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修全流程避坑手册、评论区回复关键词引导的核心逻辑。 -【开篇 & 语言要求】 -开篇沿用原文警示吐槽语气,3 秒抓眼球,点破硬装刚结束着急搬软装、忽略收尾细节入住就留隐患闹矛盾的真实痛点,瞬间引发装修完工业主共鸣。 -全程口语化大白话,通俗易懂、接地气,站业主立场拆解装修收尾细节,条理清晰、干货满满,不生硬说教,适配口播传播节奏。 -可微调句式语序,严禁篡改每一个收尾步骤的施工要求、选材建议、隐患后果等核心内容,每句带标点规范断句,拆分大长句,适配口播表达习惯。 -【内置固定原文案】 -装修千万别硬装刚结束就急着把沙发、床这些软装搬进去。先把下面这 6 个收尾的活安排明白,要不然等你人入住进去以后,两口子天天吵架。 -第一,不管你家是亮光砖还是柔光砖,趁家具还没进场,赶紧网购一瓶瓷砖除蜡剂,把地面彻底拖一遍。不然等你住进去,地面怎么都像蒙了一层水雾,看着就闹心。 -第二,餐边柜和橱柜吊柜底部建议贴一层静电防水膜,防止水蒸气慢慢把咱家的吊柜熏坏了。再有就是橱柜里边贴上铝箔纸,它防潮性会更好,而且更好打理卫生。 -第三,检查一下家里的地漏有没有断层,要是有断层,赶紧网购一个加长的地漏芯换上,不然以后排水渗到砂浆层里面,时间长了,反味儿、墙面起皮发霉,你后悔都来不及。 -第四,家具进场前一定要先安排全屋打胶,别自己打,你打不明白。尤其是你的踢脚线底下,以及厨房和卫生间窗框和瓷砖的交界处,一定记得打美容胶,别用美缝剂,美缝剂偏硬,时间长了容易脱落。 -第五,烟机和卫生间的浴霸、排风扇,你要看它有没有跟止逆阀连接。有很多安装师傅图省事儿,把排风管顺手往顶上一扔,反正你也看不着,后期全是味儿。 -第六,乳胶漆施工后记得留一些未兑水的原漆,装在密封瓶里保存,后期安装门、柜体时难免磕碰,方便随时修补。 -记不住的,我都整理在这份装修全流程避坑手册里了。评论回复避坑,拿好少踩坑。 -【内置完整素材库标题】 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -踢脚线安装验收-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近硬装收尾、软装进场、装修细节避坑主题,优先选工地恶搞、墙面空鼓、硬装完工全屋全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选美缝开荒、成品保护、收尾细节、瓷砖铺贴等贴合硬装收尾避坑主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 “等于” 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 “分镜时长” 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 “分镜文案” 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 “配音文案” 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 “5.25s”) -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “防水翻车漏水”, -“voiceover”: “新房装修刷防水,一上来就开刷的工人,直接撵走别客气!”, -“duration”: “5.75s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “他不是在赶工期,只是在图省事,这 4 点一定要做好。”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “卫生间基层清理 - 防水施工”, -“voiceover”: “第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。”, -“duration”: “5.50s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:硬装刚完工、不懂软装进场前后收尾细节、着急搬家具入住容易遗留隐患,后期发霉反味、墙面破损难修补的装修业主,围绕硬装结束必做 7 个收尾关键要点创作,按原意逻辑编排,可适度口语微调保留原意。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头硬装收尾痛点引入 + 6 个收尾避坑干货 + 结尾避坑手册引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用警示现实视角点出硬装刚完工别急着进软装,忽略 7 个收尾细节入住容易留隐患、生活闹心吵架的痛点,引出下文 6 个必做收尾关键点。 +中间核心(硬装完工 6 个收尾避坑要点,文案适当调整修改,意思保持原意,保留原有先后逻辑,不随机打乱,可口语顺滑润色): +瓷砖除蜡:亮光砖、柔光砖在家具进场前,一定要用瓷砖除蜡剂全屋拖洗一遍,避免表层蜡质残留,入住后地面发蒙有水雾感,看着别扭难打理。 +柜体防护:餐边柜、橱柜吊柜底部贴静电防水膜,阻隔水汽熏坏柜体;橱柜内部铺贴铝箔纸,提升防潮效果,日常清洁打理更省心。 +地漏整改:逐一检查全屋地漏是否存在断层,有断层及时加装加长地漏芯,防止渗水进入砂浆层,避免后期反味、墙面起皮发霉等遗留隐患。 +全屋打胶:家具进场前提前做全屋精细打胶,重点处理踢脚线底部、厨卫窗框与瓷砖交接位置,优先用美容胶,不建议用美缝剂,避免材质过硬后期脱落开裂。 +止逆阀对接:检查油烟机、卫生间浴霸和排风扇,确认排风管与止逆阀规范连接,杜绝师傅偷懒随意摆放管路,防止后期全屋倒灌异味。 +原漆留存:乳胶漆完工后预留未兑水原装漆,密封保存备用,后期装门、装柜体出现磕碰掉漆,可随时修补还原,不用整体返工刷漆。 +(备注:保留原文 7 个收尾要点的核心细节、施工逻辑、隐患后果不变,适当调整句式让口语化更贴合口播,不篡改工艺做法、选材建议、遗留隐患的核心逻辑) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:严格按原文 6 大收尾要点顺序排列,不打乱结构,贴合硬装完工到软装进场的真实施工流程,层层递进符合业主装修收尾认知逻辑。 +文案调整要求:微调仅针对句式口语化优化,把直白叙述话术改成抖音口播接地气大白话,不改变每一步施工做法、选材建议、隐患危害等所有核心信息,完整保留原文原意。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 440-480 字,按每秒 4 个纯文字计算,对应时长 110-120s,讲解收尾细节细致不啰嗦,节奏适中,适配短视频完播率。 +内容适配性:6 个收尾要点衔接自然,每一条独立适配空镜分镜,直击业主硬装完工急于入住、忽略隐蔽收尾细节,后期返工闹心的核心痛点,每一条都讲清做法、原因和避坑作用,实用性极强。 +结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修全流程避坑手册、评论区回复关键词引导的核心逻辑。 +【开篇 & 语言要求】 +开篇沿用原文警示吐槽语气,3 秒抓眼球,点破硬装刚结束着急搬软装、忽略收尾细节入住就留隐患闹矛盾的真实痛点,瞬间引发装修完工业主共鸣。 +全程口语化大白话,通俗易懂、接地气,站业主立场拆解装修收尾细节,条理清晰、干货满满,不生硬说教,适配口播传播节奏。 +可微调句式语序,严禁篡改每一个收尾步骤的施工要求、选材建议、隐患后果等核心内容,每句带标点规范断句,拆分大长句,适配口播表达习惯。 +【内置固定原文案】 +装修千万别硬装刚结束就急着把沙发、床这些软装搬进去。先把下面这 6 个收尾的活安排明白,要不然等你人入住进去以后,两口子天天吵架。 +第一,不管你家是亮光砖还是柔光砖,趁家具还没进场,赶紧网购一瓶瓷砖除蜡剂,把地面彻底拖一遍。不然等你住进去,地面怎么都像蒙了一层水雾,看着就闹心。 +第二,餐边柜和橱柜吊柜底部建议贴一层静电防水膜,防止水蒸气慢慢把咱家的吊柜熏坏了。再有就是橱柜里边贴上铝箔纸,它防潮性会更好,而且更好打理卫生。 +第三,检查一下家里的地漏有没有断层,要是有断层,赶紧网购一个加长的地漏芯换上,不然以后排水渗到砂浆层里面,时间长了,反味儿、墙面起皮发霉,你后悔都来不及。 +第四,家具进场前一定要先安排全屋打胶,别自己打,你打不明白。尤其是你的踢脚线底下,以及厨房和卫生间窗框和瓷砖的交界处,一定记得打美容胶,别用美缝剂,美缝剂偏硬,时间长了容易脱落。 +第五,烟机和卫生间的浴霸、排风扇,你要看它有没有跟止逆阀连接。有很多安装师傅图省事儿,把排风管顺手往顶上一扔,反正你也看不着,后期全是味儿。 +第六,乳胶漆施工后记得留一些未兑水的原漆,装在密封瓶里保存,后期安装门、柜体时难免磕碰,方便随时修补。 +记不住的,我都整理在这份装修全流程避坑手册里了。评论回复避坑,拿好少踩坑。 +【内置完整素材库标题】 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +踢脚线安装验收-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近硬装收尾、软装进场、装修细节避坑主题,优先选工地恶搞、墙面空鼓、硬装完工全屋全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选美缝开荒、成品保护、收尾细节、瓷砖铺贴等贴合硬装收尾避坑主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 “等于” 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 “分镜时长” 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 “分镜文案” 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 “配音文案” 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 “5.25s”) +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “防水翻车漏水”, +“voiceover”: “新房装修刷防水,一上来就开刷的工人,直接撵走别客气!”, +“duration”: “5.75s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “他不是在赶工期,只是在图省事,这 4 点一定要做好。”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “卫生间基层清理 - 防水施工”, +“voiceover”: “第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。”, +“duration”: “5.50s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修交代事项——装修师傅最讨厌业主做的6件事.txt b/python-api/app/ai/prompts/system/bk/装修交代事项——装修师傅最讨厌业主做的6件事.txt index 773db2f..3232648 100644 --- a/python-api/app/ai/prompts/system/bk/装修交代事项——装修师傅最讨厌业主做的6件事.txt +++ b/python-api/app/ai/prompts/system/bk/装修交代事项——装修师傅最讨厌业主做的6件事.txt @@ -1,261 +1,261 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:新房装修不懂行、过度干预施工细节、盲目给师傅加工序添工作量的装修业主,围绕装修师傅最讨厌业主做的 6 件事创作,按原文序号排列,不随机抽取。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点引入 + 6 件业主易踩坑行为干货 + 结尾福利引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:以 “装修师傅最讨厌业主干的 6 件事,尤其是最后一点。” 为核心句式,用警示吐槽语气点出行业真实痛点,引出下文 6 个要点(保留原文开头核心原意,适配范式结构)。 -中间核心(6 件装修师傅反感业主行为要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): -水电进场就要求全部转角做大弧弯,水流虽变大,却无形中增加师傅材料与施工成本。 -水电没完工就提前备好阻尼片、隔音棉,强行要求包厨卫下水管道,给师傅额外增加施工量。 -防水施工前执意铲掉开发商原有防水、清扫基层,虽能杜绝后期起皮开裂,却耽误师傅一整天工期。 -木工进场要求所有接缝做 V 型槽、转角做 T 字型,虽能降低墙面开裂概率,却给师傅平添大量工序。 -瓦工施工时要求卫生间先找坡度、做回形地漏,下水快又美观,但要耗费师傅半天时间重新找平。 -瓦工未完工就提前买好地漏、止逆阀,强制要求一并安装,直接断了后期安装师傅的额外收入。 -(备注:保留原文 6 个要点,按原文序号排列,保留原文核心细节和逻辑,适当调整句式让口语化更贴合口播,不篡改每层背后的利弊关系) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:严格按原文 6 个要点的序号排列,不随机抽取、不打乱顺序,保证内容连贯性,贴合家装从水电、防水、木工到瓦工的施工流程,层层递进符合业主认知。 -文案调整要求:微调仅针对句式口语化优化,改成抖音口播接地气大白话,不改变每个要点的施工场景、业主行为、带来的影响,完整保留原意不变。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解饱满不拖沓,符合短视频完播习惯。 -内容适配性:6 个要点讲解衔接自然,每点独立成段适配空镜分镜,聚焦业主不懂行乱指挥、盲目加活的通病,既讲做法又讲背后利弊,真实接地气、容易引发共鸣。 -结尾范式:以 “如果你也准备新房装修,我整理了一份装修全流程避坑手册。评论区回复避坑,拿去用。” 为核心句式,保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动核心逻辑。 -【开篇 & 语言要求】 -开篇严格遵循核心强制规则原句,3 秒抓眼球不拖沓,用真实行业视角吐槽业主盲目干预施工的通病,贴合装修受众共情点,不偏离范式结构。 -全程口语化大白话,小白易懂、不生硬说教,站客观中立角度讲解,语气接地气有真实感,贴合口播传播特点。 -可微调句式语序,严禁篡改 6 个要点的施工场景、业主行为、利弊细节,每句带标点规范断句,适配口播节奏,避免大长句。 -【内置固定原文案】 -装修师傅最讨厌业主干的 6 件事,尤其是最后一点。 -第一,水电材料刚进场,就要求师傅所有的转角全部用大弧弯,你不提师傅全用直角弯,你洗澡时倒是水流更大了,又给装修师傅增加成本。 -第二,水电还没完工,你就提前买好了黄金蜂窝阻尼片和隔音棉,非要包卫生间和阳台的下水管道,说这样不会被楼上的出水噪音吵醒,但师傅又多了些活儿。 -第三,防水师傅刚准备动手刷防水涂料,业主就喊停,让师傅把开发商原有的防水全部铲掉,再把地面打扫干净。说这样防水才不会起皮开裂。你家卫生间倒是不漏水了,做这两样活儿又要耽误师傅一天工期。 -第四,木工师傅高高兴兴来了,你却告诉他,所有接缝处都要做 V 字型槽,转角处要做到 T 字型。师傅一听就知道你是懂行的。后期墙面是不容易开裂了,又给师傅增加好多活儿。 -第五,瓦工师傅来了,懂行的业主要求把卫生间先找坡度,地漏做成回形地漏,这样不仅下水快,还好看,可这又得浪费师傅半天时间,重新找坡度。 -第六,瓦工还没结束,部分业主已经提前买好了地漏和油烟止逆阀,要求师傅一并装上。这下好了,之后安装电器的师傅想赚点外快都不行。 -如果你也准备新房装修,我整理了一份装修全流程避坑手册。评论区回复避坑,拿去用。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修施工、业主干预工序主题,优先选贴砖恶搞、墙面空鼓、水电施工等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选水电施工、防水施工、木作基层、瓷砖铺贴等贴合家装全流程主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓦工结束后不能立马验收,至少要等五六天。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “装修师傅最讨厌业主 6 件事,千万别乱干预施工” 总共 20 个文字 1 个数字,则是 "5.25s" -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "防水翻车漏水", -"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "卫生间基层清理 - 防水施工", -"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", -"duration": "5.50s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:新房装修不懂行、过度干预施工细节、盲目给师傅加工序添工作量的装修业主,围绕装修师傅最讨厌业主做的 6 件事创作,按原文序号排列,不随机抽取。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点引入 + 6 件业主易踩坑行为干货 + 结尾福利引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:以 “装修师傅最讨厌业主干的 6 件事,尤其是最后一点。” 为核心句式,用警示吐槽语气点出行业真实痛点,引出下文 6 个要点(保留原文开头核心原意,适配范式结构)。 +中间核心(6 件装修师傅反感业主行为要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): +水电进场就要求全部转角做大弧弯,水流虽变大,却无形中增加师傅材料与施工成本。 +水电没完工就提前备好阻尼片、隔音棉,强行要求包厨卫下水管道,给师傅额外增加施工量。 +防水施工前执意铲掉开发商原有防水、清扫基层,虽能杜绝后期起皮开裂,却耽误师傅一整天工期。 +木工进场要求所有接缝做 V 型槽、转角做 T 字型,虽能降低墙面开裂概率,却给师傅平添大量工序。 +瓦工施工时要求卫生间先找坡度、做回形地漏,下水快又美观,但要耗费师傅半天时间重新找平。 +瓦工未完工就提前买好地漏、止逆阀,强制要求一并安装,直接断了后期安装师傅的额外收入。 +(备注:保留原文 6 个要点,按原文序号排列,保留原文核心细节和逻辑,适当调整句式让口语化更贴合口播,不篡改每层背后的利弊关系) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:严格按原文 6 个要点的序号排列,不随机抽取、不打乱顺序,保证内容连贯性,贴合家装从水电、防水、木工到瓦工的施工流程,层层递进符合业主认知。 +文案调整要求:微调仅针对句式口语化优化,改成抖音口播接地气大白话,不改变每个要点的施工场景、业主行为、带来的影响,完整保留原意不变。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解饱满不拖沓,符合短视频完播习惯。 +内容适配性:6 个要点讲解衔接自然,每点独立成段适配空镜分镜,聚焦业主不懂行乱指挥、盲目加活的通病,既讲做法又讲背后利弊,真实接地气、容易引发共鸣。 +结尾范式:以 “如果你也准备新房装修,我整理了一份装修全流程避坑手册。评论区回复避坑,拿去用。” 为核心句式,保留原文结尾结构和领资料引导话术,仅可轻微优化口语流畅度,不改动核心逻辑。 +【开篇 & 语言要求】 +开篇严格遵循核心强制规则原句,3 秒抓眼球不拖沓,用真实行业视角吐槽业主盲目干预施工的通病,贴合装修受众共情点,不偏离范式结构。 +全程口语化大白话,小白易懂、不生硬说教,站客观中立角度讲解,语气接地气有真实感,贴合口播传播特点。 +可微调句式语序,严禁篡改 6 个要点的施工场景、业主行为、利弊细节,每句带标点规范断句,适配口播节奏,避免大长句。 +【内置固定原文案】 +装修师傅最讨厌业主干的 6 件事,尤其是最后一点。 +第一,水电材料刚进场,就要求师傅所有的转角全部用大弧弯,你不提师傅全用直角弯,你洗澡时倒是水流更大了,又给装修师傅增加成本。 +第二,水电还没完工,你就提前买好了黄金蜂窝阻尼片和隔音棉,非要包卫生间和阳台的下水管道,说这样不会被楼上的出水噪音吵醒,但师傅又多了些活儿。 +第三,防水师傅刚准备动手刷防水涂料,业主就喊停,让师傅把开发商原有的防水全部铲掉,再把地面打扫干净。说这样防水才不会起皮开裂。你家卫生间倒是不漏水了,做这两样活儿又要耽误师傅一天工期。 +第四,木工师傅高高兴兴来了,你却告诉他,所有接缝处都要做 V 字型槽,转角处要做到 T 字型。师傅一听就知道你是懂行的。后期墙面是不容易开裂了,又给师傅增加好多活儿。 +第五,瓦工师傅来了,懂行的业主要求把卫生间先找坡度,地漏做成回形地漏,这样不仅下水快,还好看,可这又得浪费师傅半天时间,重新找坡度。 +第六,瓦工还没结束,部分业主已经提前买好了地漏和油烟止逆阀,要求师傅一并装上。这下好了,之后安装电器的师傅想赚点外快都不行。 +如果你也准备新房装修,我整理了一份装修全流程避坑手册。评论区回复避坑,拿去用。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修施工、业主干预工序主题,优先选贴砖恶搞、墙面空鼓、水电施工等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选水电施工、防水施工、木作基层、瓷砖铺贴等贴合家装全流程主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,瓦工结束后不能立马验收,至少要等五六天。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “装修师傅最讨厌业主 6 件事,千万别乱干预施工” 总共 20 个文字 1 个数字,则是 "5.25s" +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "防水翻车漏水", +"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "卫生间基层清理 - 防水施工", +"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", +"duration": "5.50s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修合同干货——装修合同三大避坑干货.txt b/python-api/app/ai/prompts/system/bk/装修合同干货——装修合同三大避坑干货.txt index 209e042..ab48b3b 100644 --- a/python-api/app/ai/prompts/system/bk/装修合同干货——装修合同三大避坑干货.txt +++ b/python-api/app/ai/prompts/system/bk/装修合同干货——装修合同三大避坑干货.txt @@ -1,260 +1,260 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备签装修合同、不懂条款陷阱、容易被低价全包套路、后期增项加价被牵制的装修业主,围绕装修签约必盯 3 大核心要点及备注条款创作,按原文逻辑顺序排列,不随机抽取。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头签约痛点引入 + 合同 3 大避坑干货 + 结尾合同模板引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用扎心现实视角点出签合同前后地位反差、低价全包后期翻倍加价的痛点,引出下文 3 个必盯关键点。 -中间核心(装修合同 3 大避坑要点 + 备注条款,文案适当调整修改,意思保持原意,按原文逻辑顺序排列,不随机抽取): -违约金条款:装修公司常设 20% 至 30% 高额违约条款,无施工反悔也要高额赔付,签约务必改成 3%,把自身风险降到最低。 -付款节点:拒绝 60%、80% 高首付套路,手握资金才有主动权;按 15% 开工、30% 水电验收、30% 木瓦工验收、20% 油工验收、5% 竣工尾款的标准付款最稳妥。 -合同备注栏:一定要逐条补充关键约定,涵盖环保建材检测、工地安全责任、结构隐患追责、工期延误赔付、赠送家电安装节点五大保障内容,全方位约束装修公司。 -(备注:保留原文 3 大要点及 5 条备注核心细节、数字比例、责任约定不变,适当调整句式让口语化更贴合口播,不篡改条款利弊、付款比例、赔付规则核心逻辑) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:严格按原文违约金、付款方式、备注栏三大板块顺序排列,不打乱结构,贴合业主签合同逐条审核的真实流程,层层递进符合认知逻辑。 -文案调整要求:微调仅针对句式口语化优化,把书面合同话术改成抖音口播接地气大白话,不改变违约金比例、付款节点金额、备注 5 条硬性约定等所有核心数字和规则,完整保留原文原意。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解条款细致不啰嗦,节奏适中,适配短视频完播率。 -内容适配性:三大要点及备注条款衔接自然,每部分独立适配空镜分镜,直击业主签约被套路、后期加价维权难的核心痛点,每一条都讲清陷阱、整改方法和保障作用,实用性极强。 -结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修合同模板、评论区回复关键词引导的核心逻辑。 -【开篇 & 语言要求】 -开篇沿用原文扎心吐槽语气,3 秒抓眼球,点破装修签合同前后身份反差、低价全包套路深坑,瞬间引发准备装修业主共鸣。 -全程口语化大白话,通俗易懂、接地气,站业主立场拆解合同陷阱,条理清晰、干货满满,不生硬说教,适配口播传播节奏。 -可微调句式语序,严禁篡改违约金比例、付款节点数值、备注五条约定的核心内容和硬性规则,每句带标点规范断句,拆分大长句,适配口播表达习惯。 -【内置固定原文案】 -装修签合同前你是上帝,签完合同立刻变成弱势群体。装修签合同说好了 10 万全包,最后装完你要花 20 万,不给钱还要起诉你,抓住我下面说的 3 点,盯紧了,后期绝对少遭罪。 -第一个违约金,很多装修公司填百分之二十、三十,要是反悔了,什么也没干,就得赔两万,这就是把你绑死的条款。签合同必须改成 3%,最多亏 3000,把风险降到最低。 -第二个付款方式,别被百分之六十、百分之八十的首付款给坑了。钱一交就没有主动权,工地出问题只能被动整改。按我说的,签合同时付 15%,水电防水等隐蔽工程验收合格后付 30%,瓦工、木工验收合格了付 30%,油工验收合格了付 20%,竣工验收没问题,再付最后的 5%。钱在手里才有主动权。 -第三个备注栏,这是个保障,千万别忽略,照着填: -1,乙方承诺使用环保建材,施工完成后,甲方可在自主材料未进场时进行空气检测,环保不达标,乙方全额返还所有施工费用。 -2,工地及工人的人身安全由乙方全权负责,甲方不承担任何责任。 -3,因设计和施工造成的房屋、墙体等结构安全隐患,由乙方全权负责。 -4,若乙方原因延误工期,每延误一天,支付工程款总费用的 1%。 -5,乙方承诺赠送的家电,必须在甲方支付最后一笔工程款之前安装到位。 -合同这么签,谁都坑不了你。记不住的,我整理了装修合同模板,回复合同拿去用,对着谈准没错。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修合同签约、条款避坑主题,优先选工地恶搞、装修合同核对、毛坯全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选装修合同核对、现场交底、全屋验收等贴合合同签约避坑主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "防水翻车漏水", -"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "卫生间基层清理 - 防水施工", -"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", -"duration": "5.50s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备签装修合同、不懂条款陷阱、容易被低价全包套路、后期增项加价被牵制的装修业主,围绕装修签约必盯 3 大核心要点及备注条款创作,按原文逻辑顺序排列,不随机抽取。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头签约痛点引入 + 合同 3 大避坑干货 + 结尾合同模板引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用扎心现实视角点出签合同前后地位反差、低价全包后期翻倍加价的痛点,引出下文 3 个必盯关键点。 +中间核心(装修合同 3 大避坑要点 + 备注条款,文案适当调整修改,意思保持原意,按原文逻辑顺序排列,不随机抽取): +违约金条款:装修公司常设 20% 至 30% 高额违约条款,无施工反悔也要高额赔付,签约务必改成 3%,把自身风险降到最低。 +付款节点:拒绝 60%、80% 高首付套路,手握资金才有主动权;按 15% 开工、30% 水电验收、30% 木瓦工验收、20% 油工验收、5% 竣工尾款的标准付款最稳妥。 +合同备注栏:一定要逐条补充关键约定,涵盖环保建材检测、工地安全责任、结构隐患追责、工期延误赔付、赠送家电安装节点五大保障内容,全方位约束装修公司。 +(备注:保留原文 3 大要点及 5 条备注核心细节、数字比例、责任约定不变,适当调整句式让口语化更贴合口播,不篡改条款利弊、付款比例、赔付规则核心逻辑) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:严格按原文违约金、付款方式、备注栏三大板块顺序排列,不打乱结构,贴合业主签合同逐条审核的真实流程,层层递进符合认知逻辑。 +文案调整要求:微调仅针对句式口语化优化,把书面合同话术改成抖音口播接地气大白话,不改变违约金比例、付款节点金额、备注 5 条硬性约定等所有核心数字和规则,完整保留原文原意。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解条款细致不啰嗦,节奏适中,适配短视频完播率。 +内容适配性:三大要点及备注条款衔接自然,每部分独立适配空镜分镜,直击业主签约被套路、后期加价维权难的核心痛点,每一条都讲清陷阱、整改方法和保障作用,实用性极强。 +结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修合同模板、评论区回复关键词引导的核心逻辑。 +【开篇 & 语言要求】 +开篇沿用原文扎心吐槽语气,3 秒抓眼球,点破装修签合同前后身份反差、低价全包套路深坑,瞬间引发准备装修业主共鸣。 +全程口语化大白话,通俗易懂、接地气,站业主立场拆解合同陷阱,条理清晰、干货满满,不生硬说教,适配口播传播节奏。 +可微调句式语序,严禁篡改违约金比例、付款节点数值、备注五条约定的核心内容和硬性规则,每句带标点规范断句,拆分大长句,适配口播表达习惯。 +【内置固定原文案】 +装修签合同前你是上帝,签完合同立刻变成弱势群体。装修签合同说好了 10 万全包,最后装完你要花 20 万,不给钱还要起诉你,抓住我下面说的 3 点,盯紧了,后期绝对少遭罪。 +第一个违约金,很多装修公司填百分之二十、三十,要是反悔了,什么也没干,就得赔两万,这就是把你绑死的条款。签合同必须改成 3%,最多亏 3000,把风险降到最低。 +第二个付款方式,别被百分之六十、百分之八十的首付款给坑了。钱一交就没有主动权,工地出问题只能被动整改。按我说的,签合同时付 15%,水电防水等隐蔽工程验收合格后付 30%,瓦工、木工验收合格了付 30%,油工验收合格了付 20%,竣工验收没问题,再付最后的 5%。钱在手里才有主动权。 +第三个备注栏,这是个保障,千万别忽略,照着填: +1,乙方承诺使用环保建材,施工完成后,甲方可在自主材料未进场时进行空气检测,环保不达标,乙方全额返还所有施工费用。 +2,工地及工人的人身安全由乙方全权负责,甲方不承担任何责任。 +3,因设计和施工造成的房屋、墙体等结构安全隐患,由乙方全权负责。 +4,若乙方原因延误工期,每延误一天,支付工程款总费用的 1%。 +5,乙方承诺赠送的家电,必须在甲方支付最后一笔工程款之前安装到位。 +合同这么签,谁都坑不了你。记不住的,我整理了装修合同模板,回复合同拿去用,对着谈准没错。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修合同签约、条款避坑主题,优先选工地恶搞、装修合同核对、毛坯全景等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选装修合同核对、现场交底、全屋验收等贴合合同签约避坑主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "防水翻车漏水", +"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "卫生间基层清理 - 防水施工", +"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", +"duration": "5.50s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修合同要点——装修签合同要注意的4点.txt b/python-api/app/ai/prompts/system/bk/装修合同要点——装修签合同要注意的4点.txt index dc9beb7..710c69e 100644 --- a/python-api/app/ai/prompts/system/bk/装修合同要点——装修签合同要注意的4点.txt +++ b/python-api/app/ai/prompts/system/bk/装修合同要点——装修签合同要注意的4点.txt @@ -1,260 +1,260 @@ -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:即将签订装修合同、担心合同条款有陷阱、怕被装修公司钻文字空子坑钱的业主,严格围绕装修合同避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 随机4点合同避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏9:16拍摄 -【核心强制规则】 -开头范式:以“新房装修【核心场景:签合同】,谁要是给你一上来就【错误操作:拿模糊条款合同】,你就直接【拒绝动作:别签他】。你以为他是帮你【表面好处:省麻烦、省时间】,其实他就是图【错误目的:钻文字空子、坑你钱】。下面这4点一定要看仔细,少看一条都可能亏几万!”为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(6个装修合同避坑要点,文案适当调整修改,意思保持原意,随机抽取4个重编序号): -1. 工期陷阱:平层硬装90个自然日足够,扣除周末不施工,实际干活六七十天。没约定工期可能拖一年半载。 -2. 延期赔偿:延期一天赔万分之二不合理,按6万半包算一天才12元,拖一个月才360元。延期赔偿必须按每天2‰写。 -3. 付款方式:必须验收后付,不是验收前。建议:签完合同时付15%,水电验收完付30%,泥木工验收完付30%,涂料验收完付20%,全部竣工验收完再付5%。 -4. 材料调换坑:条款写着材料断货可用同等价钱调换,这条是偷工减料的正当理由。等价杂牌不敢用,必须划掉这条。 -5. 安全责任:80%的公司只写按安全标准施工,但出事谁负责?合同必须注明工人人身安全及财产损失全部由装修公司承担。 -6. 违约金恶心点:单方面解约违约金写得很高,公司不会主动解约,就是为了绑死客户。违约金超过20%直接拉黑,别犹豫。 -(备注:随机抽取上述4点作为中间核心,重编序号,保留原文核心数据和避坑逻辑,适当调整句式让口语化更贴合口播) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑指南】,回复【核心关键词:合同】直接拿走,对照检查,少踩坑!” -【开篇&语言要求】 -开篇1–2句话钩子,直击装修合同文字陷阱、被装修公司坑钱的痛点,3秒抓眼球,不拖沓不铺垫(保留原文“玩的都是文字游戏,少踩一个坑等于多赚一笔钱”核心钩子)。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调句式,不得篡改原文中工期、赔偿金比例、付款节点、材料条款等核心数字数据,每句必须带标点断句。 -【细节固定要求】 -结尾必须固定话术:我整理了装修全流程避坑指南,回复合同直接拿走。同时保留原文结尾“记不住的,我整理了装修合同样本,评论区回复合同,直接拿着对照检查,少踩坑!” -总分镜数量固定12–20个,每个分镜时长3–8秒,可保留两位小数。 -【内置固定原文案】 -新房装修签合同千万注意这6个点,玩的都是文字游戏,耐心听我讲完,少踩一个坑等于多赚一笔钱。 -第一,工期。一般平层硬装90个自然日就足够了,扣除周末不能施工,真正干活六七十天完全可行。你要是没约定好,装修公司给你拖个一年半载,你哭都没地方。 -第二,延期赔偿金。延误工期后,很多公司写延期一天赔万分之二,按6万半包算,一天才12块钱,拖一个月才360块钱。你觉得有约束力吗?工期咱可以自己宽限,但延期赔偿一定要按每天2‰来写。 -第三,付款方式。一定要按我说的,记住付款节点一定要写清楚,是验收后付,不是验收前。比如,签完合同时付15%,水电验收完付30%,泥木工验收完付30%,涂料验收完付20%,全部竣工验收完再付5%。 -第四,材料调换坑。很多公司条款上面写着,当材料断货时,可用同等价钱调换,但有这条,偷工减料就成了理所当然。同价产品很难界定,同价的杂牌你敢用吗?这条必须划掉。 -第五,安全责任。有80%的公司只写按安全标准施工,但别不提出事谁负责?一旦发生安全事故,就是扯不完的皮。合同里必须注明工人人身安全及财产损失全部由装修公司承担。 -第六,也是最恶心的一点,很多公司把单方面解约违约金写得很高,他们根本不会主动解约,这条就是为了绑死你。违约金超过20%,你发现问题也不敢换人,所以超过20%直接拉黑,别犹豫。 -记不住的,我整理了装修合同样本,评论区回复合同,直接拿走对照检查,少踩坑! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近合同主题,优先选装修合同核对、工地恶搞相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选合同签署、装修合同核对等贴合合同主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,装修报价别只看总价,漏一项,后期就得多花好几万。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" -type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离440–480(含数字,不含标点符号)、总时长偏离110–120秒。 -禁止篡改原文合同避坑相关的工期、赔偿金比例、付款节点等核心数据。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “工地恶搞 - 恶搞开篇”, -“voiceover”: “新房装修签合同,全是文字游戏,少踩坑等于多赚钱”, -“duration”: “5.25s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “拿模糊条款合同给你的装修公司,直接别签别客气”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “装修合同核对 - 现场交底”, -“voiceover”: “他不是省麻烦,是想钻空子坑你钱,这4点必看”, -“duration”: “4.75s” -} +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:即将签订装修合同、担心合同条款有陷阱、怕被装修公司钻文字空子坑钱的业主,严格围绕装修合同避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 随机4点合同避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏9:16拍摄 +【核心强制规则】 +开头范式:以“新房装修【核心场景:签合同】,谁要是给你一上来就【错误操作:拿模糊条款合同】,你就直接【拒绝动作:别签他】。你以为他是帮你【表面好处:省麻烦、省时间】,其实他就是图【错误目的:钻文字空子、坑你钱】。下面这4点一定要看仔细,少看一条都可能亏几万!”为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(6个装修合同避坑要点,文案适当调整修改,意思保持原意,随机抽取4个重编序号): +1. 工期陷阱:平层硬装90个自然日足够,扣除周末不施工,实际干活六七十天。没约定工期可能拖一年半载。 +2. 延期赔偿:延期一天赔万分之二不合理,按6万半包算一天才12元,拖一个月才360元。延期赔偿必须按每天2‰写。 +3. 付款方式:必须验收后付,不是验收前。建议:签完合同时付15%,水电验收完付30%,泥木工验收完付30%,涂料验收完付20%,全部竣工验收完再付5%。 +4. 材料调换坑:条款写着材料断货可用同等价钱调换,这条是偷工减料的正当理由。等价杂牌不敢用,必须划掉这条。 +5. 安全责任:80%的公司只写按安全标准施工,但出事谁负责?合同必须注明工人人身安全及财产损失全部由装修公司承担。 +6. 违约金恶心点:单方面解约违约金写得很高,公司不会主动解约,就是为了绑死客户。违约金超过20%直接拉黑,别犹豫。 +(备注:随机抽取上述4点作为中间核心,重编序号,保留原文核心数据和避坑逻辑,适当调整句式让口语化更贴合口播) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑指南】,回复【核心关键词:合同】直接拿走,对照检查,少踩坑!” +【开篇&语言要求】 +开篇1–2句话钩子,直击装修合同文字陷阱、被装修公司坑钱的痛点,3秒抓眼球,不拖沓不铺垫(保留原文“玩的都是文字游戏,少踩一个坑等于多赚一笔钱”核心钩子)。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调句式,不得篡改原文中工期、赔偿金比例、付款节点、材料条款等核心数字数据,每句必须带标点断句。 +【细节固定要求】 +结尾必须固定话术:我整理了装修全流程避坑指南,回复合同直接拿走。同时保留原文结尾“记不住的,我整理了装修合同样本,评论区回复合同,直接拿着对照检查,少踩坑!” +总分镜数量固定12–20个,每个分镜时长3–8秒,可保留两位小数。 +【内置固定原文案】 +新房装修签合同千万注意这6个点,玩的都是文字游戏,耐心听我讲完,少踩一个坑等于多赚一笔钱。 +第一,工期。一般平层硬装90个自然日就足够了,扣除周末不能施工,真正干活六七十天完全可行。你要是没约定好,装修公司给你拖个一年半载,你哭都没地方。 +第二,延期赔偿金。延误工期后,很多公司写延期一天赔万分之二,按6万半包算,一天才12块钱,拖一个月才360块钱。你觉得有约束力吗?工期咱可以自己宽限,但延期赔偿一定要按每天2‰来写。 +第三,付款方式。一定要按我说的,记住付款节点一定要写清楚,是验收后付,不是验收前。比如,签完合同时付15%,水电验收完付30%,泥木工验收完付30%,涂料验收完付20%,全部竣工验收完再付5%。 +第四,材料调换坑。很多公司条款上面写着,当材料断货时,可用同等价钱调换,但有这条,偷工减料就成了理所当然。同价产品很难界定,同价的杂牌你敢用吗?这条必须划掉。 +第五,安全责任。有80%的公司只写按安全标准施工,但别不提出事谁负责?一旦发生安全事故,就是扯不完的皮。合同里必须注明工人人身安全及财产损失全部由装修公司承担。 +第六,也是最恶心的一点,很多公司把单方面解约违约金写得很高,他们根本不会主动解约,这条就是为了绑死你。违约金超过20%,你发现问题也不敢换人,所以超过20%直接拉黑,别犹豫。 +记不住的,我整理了装修合同样本,评论区回复合同,直接拿走对照检查,少踩坑! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近合同主题,优先选装修合同核对、工地恶搞相关)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选合同签署、装修合同核对等贴合合同主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +“分镜文案"等于"配音文案”,“配音文案”必须要有标点符号断句,避免大长句,如:“第一,装修报价别只看总价,漏一项,后期就得多花好几万。”每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的"分镜时长"为{严格按**每秒4个纯文字**计算时长。文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算,即"分镜文案"的纯文字字数/4},严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s" +type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离440–480(含数字,不含标点符号)、总时长偏离110–120秒。 +禁止篡改原文合同避坑相关的工期、赔偿金比例、付款节点等核心数据。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “工地恶搞 - 恶搞开篇”, +“voiceover”: “新房装修签合同,全是文字游戏,少踩坑等于多赚钱”, +“duration”: “5.25s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “拿模糊条款合同给你的装修公司,直接别签别客气”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “装修合同核对 - 现场交底”, +“voiceover”: “他不是省麻烦,是想钻空子坑你钱,这4点必看”, +“duration”: “4.75s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修合同避坑——8 条装修合同避坑干货.txt b/python-api/app/ai/prompts/system/bk/装修合同避坑——8 条装修合同避坑干货.txt index 7c9edec..7ff675c 100644 --- a/python-api/app/ai/prompts/system/bk/装修合同避坑——8 条装修合同避坑干货.txt +++ b/python-api/app/ai/prompts/system/bk/装修合同避坑——8 条装修合同避坑干货.txt @@ -1,262 +1,262 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备新房装修、即将签署装修合同,担心直接签装修公司固定模板踩坑、后期扯皮加价、权益无保障的业主,严格围绕装修合同 8 条必签避坑要点创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 8 条装修合同避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:以 “新房装修【核心场景:签装修合同】,谁要是直接照搬【错误操作:装修公司固定模板】就签字,你就直接【拒绝动作:别盲目乱签】。你以为他是帮你【表面好处:省事、不用自己琢磨】,其实他就是图【错误目的:埋下陷阱、后期挖坑加价】。下面这 8 条一定要白纸黑字写进合同,少一条都保不住自身权益!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 -中间核心(8 条装修合同避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): -工期保修:合同写清施工工期和售后保修期,杜绝工期拖延、工程烂尾,后期维修费用由装修公司全权承担,避免出问题不认账。 -安全责任:明确划分施工安全责任,砸拆承重墙、工人施工意外等所有责任,全部由装修公司承担,避免业主无辜承担损失、被工人碰瓷。 -总价税金:锁定合同固定总价,标注是否含税,竣工结算严禁随意调价,项目变更价款控制在 5% 以内,杜绝恶意增项乱加钱。 -付款比例:约定按施工节点比例付款,每环节验收合格再支付款项,不提前大额预交,建议签合同仅付 15%,大幅降低装修风险。 -工程验收:按行业新标准执行分段验收,每道工序完工必须通知业主到场,验收合格方可进入下一步,禁止跳过验收埋下质量隐患。 -材料约定:写明材料品牌型号规格,落实假一罚十条款,所有材料需业主确认无误后再施工,防止装修公司以次充好、偷换主材。 -甲醛整改:约定全屋甲醛检测若不合格,由装修公司负责免费整改,并承担全部相关费用,避免入住甲醛超标、维权无门。 -违约赔付:明确双方违约责任,写清违约金比例和逾期赔付金额,约束双方行为,让装修公司不敢随意违约、敷衍施工。 -(备注:保留原文 8 个要点,按原文序号排列,保留原文核心数据、条款逻辑与避坑内涵,微调句式适配口播,严格控制纯文字 + 数字字数 400-440 字,适配时长 100-110s) -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修标准合同模板】,回复【核心关键词:装修】直接拿走,对照检查,少踩坑!” -【开篇 & 语言要求】 -开篇钩子,直击装修签合同盲目乱签、被模板套路、后期权益受损的痛点,3 秒抓眼球,不拖沓不铺垫(保留原文 “准备装修的家人们注意了!签合同别瞎签,装修公司固定模板直接签必踩坑” 核心钩子)。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调句式,不得篡改原文合同工期、付款比例、变更价款 5%、15% 预付款等核心数字与权责逻辑,每句必须带标点断句。 -【内置固定原文案】 -准备装修的家人们注意了!签合同别瞎签,装修公司的固定模板,直接签必踩坑!下面这 8 条,必须白纸黑字写清楚,才能保住你的权益! -第一,写清工期和保修期,防止脱工烂尾,保修费全由装修公司承担。不然装修公司拖工期、后期出问题不认账,你没处说理。 -第二,安全责任分清楚,砸承重墙、工人出事,全由装修公司负责。别被工人碰瓷,最后自己承担不必要的损失。 -第三,固定合同总价,含不含税金写明白,结算不随意调价,变更价款不超 5%。避免装修公司乱加钱,保障自身权益。 -第四,按比例付款,验收合格再给钱,别一上来交太多。签合同付 15%,验收合格再付剩余部分,降低风险。 -第五,工程验收按新标准,每个环节必须通知你,验收合格再下一步。不让装修公司跳过验收,埋下质量隐患。 -第六,材料假一罚十,品牌型号对好,你确认后再施工。防止装修公司以次充好,偷换材料。 -第七,甲醛检测不合格,装修公司整改并承担所有费用。避免入住后甲醛超标,维权无门。 -第八,违约责任划清楚,违约金和逾期赔付金额写明白。保障自己权益,让装修公司不敢随意违约。 -准备装修的,我整理了合同模板,评论区回复装修就能领!帮你装修少踩坑、省麻烦! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修合同主题,优先选工地恶搞、装修合同核对、合同签署等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选合同签署、装修合同核对、施工方案现场讲解等贴合合同签约主题的空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,装修报价别只看总价,漏一项,后期就得多花好几万。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s" -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -禁止总字数偏离 400–440(含数字,不含标点符号)、总时长偏离 100–110 秒。 -禁止篡改原文装修合同避坑相关的工期、付款比例、变更价款、权责划分等核心数据和逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “工地恶搞 - 恶搞开篇”, -“voiceover”: “新房装修签合同,全是文字游戏,少踩坑等于多赚钱”, -“duration”: “5.25s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “拿固定模板合同给你的装修公司,千万别直接签”, -“duration”: “5s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “装修合同核对 - 现场交底”, -“voiceover”: “8 条条款必须写进合同,条条守住你的装修权益”, -“duration”: “5s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备新房装修、即将签署装修合同,担心直接签装修公司固定模板踩坑、后期扯皮加价、权益无保障的业主,严格围绕装修合同 8 条必签避坑要点创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 8 条装修合同避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:以 “新房装修【核心场景:签装修合同】,谁要是直接照搬【错误操作:装修公司固定模板】就签字,你就直接【拒绝动作:别盲目乱签】。你以为他是帮你【表面好处:省事、不用自己琢磨】,其实他就是图【错误目的:埋下陷阱、后期挖坑加价】。下面这 8 条一定要白纸黑字写进合同,少一条都保不住自身权益!” 为核心句式,用警示性语气点出常见坑,引出下文要点(保留原文开头核心原意,适配范式结构)。 +中间核心(8 条装修合同避坑要点,文案适当调整修改,意思保持原意,按原文序号排列,不随机抽取): +工期保修:合同写清施工工期和售后保修期,杜绝工期拖延、工程烂尾,后期维修费用由装修公司全权承担,避免出问题不认账。 +安全责任:明确划分施工安全责任,砸拆承重墙、工人施工意外等所有责任,全部由装修公司承担,避免业主无辜承担损失、被工人碰瓷。 +总价税金:锁定合同固定总价,标注是否含税,竣工结算严禁随意调价,项目变更价款控制在 5% 以内,杜绝恶意增项乱加钱。 +付款比例:约定按施工节点比例付款,每环节验收合格再支付款项,不提前大额预交,建议签合同仅付 15%,大幅降低装修风险。 +工程验收:按行业新标准执行分段验收,每道工序完工必须通知业主到场,验收合格方可进入下一步,禁止跳过验收埋下质量隐患。 +材料约定:写明材料品牌型号规格,落实假一罚十条款,所有材料需业主确认无误后再施工,防止装修公司以次充好、偷换主材。 +甲醛整改:约定全屋甲醛检测若不合格,由装修公司负责免费整改,并承担全部相关费用,避免入住甲醛超标、维权无门。 +违约赔付:明确双方违约责任,写清违约金比例和逾期赔付金额,约束双方行为,让装修公司不敢随意违约、敷衍施工。 +(备注:保留原文 8 个要点,按原文序号排列,保留原文核心数据、条款逻辑与避坑内涵,微调句式适配口播,严格控制纯文字 + 数字字数 400-440 字,适配时长 100-110s) +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修标准合同模板】,回复【核心关键词:装修】直接拿走,对照检查,少踩坑!” +【开篇 & 语言要求】 +开篇钩子,直击装修签合同盲目乱签、被模板套路、后期权益受损的痛点,3 秒抓眼球,不拖沓不铺垫(保留原文 “准备装修的家人们注意了!签合同别瞎签,装修公司固定模板直接签必踩坑” 核心钩子)。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调句式,不得篡改原文合同工期、付款比例、变更价款 5%、15% 预付款等核心数字与权责逻辑,每句必须带标点断句。 +【内置固定原文案】 +准备装修的家人们注意了!签合同别瞎签,装修公司的固定模板,直接签必踩坑!下面这 8 条,必须白纸黑字写清楚,才能保住你的权益! +第一,写清工期和保修期,防止脱工烂尾,保修费全由装修公司承担。不然装修公司拖工期、后期出问题不认账,你没处说理。 +第二,安全责任分清楚,砸承重墙、工人出事,全由装修公司负责。别被工人碰瓷,最后自己承担不必要的损失。 +第三,固定合同总价,含不含税金写明白,结算不随意调价,变更价款不超 5%。避免装修公司乱加钱,保障自身权益。 +第四,按比例付款,验收合格再给钱,别一上来交太多。签合同付 15%,验收合格再付剩余部分,降低风险。 +第五,工程验收按新标准,每个环节必须通知你,验收合格再下一步。不让装修公司跳过验收,埋下质量隐患。 +第六,材料假一罚十,品牌型号对好,你确认后再施工。防止装修公司以次充好,偷换材料。 +第七,甲醛检测不合格,装修公司整改并承担所有费用。避免入住后甲醛超标,维权无门。 +第八,违约责任划清楚,违约金和逾期赔付金额写明白。保障自己权益,让装修公司不敢随意违约。 +准备装修的,我整理了合同模板,评论区回复装修就能领!帮你装修少踩坑、省麻烦! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近装修合同主题,优先选工地恶搞、装修合同核对、合同签署等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选合同签署、装修合同核对、施工方案现场讲解等贴合合同签约主题的空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,如:“第一,装修报价别只看总价,漏一项,后期就得多花好几万。” 每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s" +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +禁止总字数偏离 400–440(含数字,不含标点符号)、总时长偏离 100–110 秒。 +禁止篡改原文装修合同避坑相关的工期、付款比例、变更价款、权责划分等核心数据和逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “工地恶搞 - 恶搞开篇”, +“voiceover”: “新房装修签合同,全是文字游戏,少踩坑等于多赚钱”, +“duration”: “5.25s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “拿固定模板合同给你的装修公司,千万别直接签”, +“duration”: “5s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “装修合同核对 - 现场交底”, +“voiceover”: “8 条条款必须写进合同,条条守住你的装修权益”, +“duration”: “5s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修常见问题——装修必问的18个问题.txt b/python-api/app/ai/prompts/system/bk/装修常见问题——装修必问的18个问题.txt index c9bf478..74bc6f2 100644 --- a/python-api/app/ai/prompts/system/bk/装修常见问题——装修必问的18个问题.txt +++ b/python-api/app/ai/prompts/system/bk/装修常见问题——装修必问的18个问题.txt @@ -1,296 +1,296 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:准备找装修公司、不懂怎么咨询避坑、容易被低价套路、前期没问清后期疯狂增项多花冤枉钱的业主,围绕装修 18 个必问核心问题做避坑口播内容,帮业主提前问清关键要点,规避装修陷阱。 -(二)脚本类型 -装修咨询避坑口播短视频脚本,结构固定:保留原版完整开头 + 18 个问题随机打乱重新编排顺序、适度口语微调 + 保留原版完整结尾引导,无多余内容,不增减问题数量,不篡改核心逻辑。 -【平台适配】 -竖屏 9:16 拍摄,适配抖音、视频号口播节奏,适合中长干货类短视频,兼顾完播率和实用性。 -【核心强制规则】 -开头范式 -完整保留原文开头一字不变:装修不懂问这几个问题,至少让你亏几万。沿用警示性痛点语气,直击业主不懂咨询、容易被装修公司套路亏钱的核心痛点,简洁有力,3 秒抓眼球,引出下文 18 个必问问题,不改写、不替换、不重新创作开头,不添加任何多余话术。 -中间核心 -1、 严格保留全部18 个问题原文核心原意,不删减、不新增、不篡改任何问题内涵、关键询问点和核心诉求; -2、 每次生成都自动随机打乱 18 个问题的排列顺序,重新自主编排,不固定顺序,每次生成均为不同排列组合; -3、 可适当做口语化顺滑微调、精简冗余语气词,适配口播语感,让语句更自然接地气,但不能改变问题本意、关键信息和询问方向; -4、 纯文字 + 数字扣除标点严格锁定 440-480 字,对应时长110-120s,按每秒 4 个字核算,不偏离字数和时长区间,确保内容饱满不拖沓。 -18 个装修必问原始问题汇总 -1、前期承诺我免费设计和量房,后期不会又问我要两三千设计费吧? -2、目前在施工的有几家,能领我上现场看看不? -3、装修全程是不是只用一个人对接? -4、交完定金我不想找你装修了,是全款退还是扣我违约金? -5、工地是自己的工人还是外包的? -6、合同签完啥时候能开工? -7、全程节点验收是多少次?要不要我每次都到现场签字? -8、要是我没空跑工地,怎么了解工地的进度? -9、能不能给我你家的标准施工流程和验收规范? -10、水电是怎么走线和收费的? -11、材料都是什么品牌?环保等级能达到什么标准? -12、拆墙垃圾包不包清运下楼?垃圾清运费咋算的? -13、卫生间防水标准是多少?厨房做防水要不要单独加钱? -14、过门石、踢脚线这些玩意儿是不是另算钱? -15、展厅主材随便选吗?套餐内有什么限制? -16、橱柜限不限米数和形状,增项的地方在哪里? -17、装修工期多长时间能装完?如果延期了怎么赔? -18、售后保几年?水电、防水、基础施工、主材都得说清楚。 -结尾范式 -完整保留原文结尾原话一字不变:想知道这些问题的标准答案,我都整理在装修避坑手册里了,回个避坑直接拿去。不改动引流逻辑、不改写语句、不新增多余话术,保持原有引流引导的简洁性和实用性。 -【开篇 & 语言要求】 -开篇完全沿用原版固定文案,不做任何修改,直击装修咨询踩坑、亏钱痛点,3 秒抓住装修业主注意力,不拖沓、不铺垫; -全程采用接地气大白话、内行唠嗑口吻,贴合普通业主咨询装修的真实语境,不生硬说教、不堆砌专业术语,让小白业主一听就懂; -仅可微调 18 个问题的语序、顺滑口语表达,删减冗余语气词(不改变原意),严禁篡改 18 个问题的核心询问点、关键诉求和关键信息; -每句必须带标点规范断句,适配口播节奏,避免超长句子,确保语速平缓、干货清晰,贴合中长干货类短视频的完播习惯。 -【内置固定原文案】 -装修不懂问这几个问题,至少让你亏几万 -第一问,前期承诺我免费设计和量房,后期不会又问我要两三千设计费吧? -第二问,目前在施工的有几家,能领我上现场看看不? -第三问,装修全程是不是只用一个人对接? -第四问,交完定金我不想找你装修了,是全款退还是扣我违约金? -第五问,工地是自己的工人还是外包的? -第六问,合同签完啥时候能开工? -第七问,全程节点验收是多少次?要不要我每次都到现场签字? -第八问,要是我没空跑工地,怎么了解工地的进度? -第九问,能不能给我你家的标准施工流程和验收规范? -第十问,水电是怎么走线和收费的? -第十一问,材料都是什么品牌?环保等级能达到什么标准? -第十二问,拆墙垃圾包不包清运下楼?垃圾清运费咋算的? -第十三问,卫生间防水标准是多少?厨房做防水要不要单独加钱? -第十四问,过门石、踢脚线这些玩意儿是不是另算钱? -第十五问,展厅主材随便选吗?套餐内有什么限制? -第十六问,橱柜限不限米数和形状,增项的地方在哪里? -第十七问,装修工期多长时间能装完?如果延期了怎么赔? -第十八问,售后保几年?水电、防水、基础施工、主材都得说清楚。 -想知道这些问题的标准答案,我都整理在装修避坑手册里了,回个避坑直接拿去 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴近装修咨询、装修套路、施工避坑主题,优先选工地恶搞、装修合同核对、施工翻车镜等相关素材)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜,确保开篇画面有吸睛点、有人物共情、有场景铺垫。 -分点阐述(18 个问题)全部用空镜,空镜素材库标题与文案内容需精准匹配(如咨询合同相关问题,匹配 “装修合同核对”;咨询水电相关问题,匹配 “水电验收”“水路施工” 等),匹配不到则优先选现场交底、量房勘测、主材安装等装修相关近似空镜,确保画面与配音高度契合。 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜,空镜优先选装修避坑相关、成品验收相关素材,呼应结尾引流引导。 -分镜文案 = 配音文案,必须要有标点符号断句,避免大长句;每段分镜文案纯文字含数字、不含标点严格控制 12-32 个字,超长句必须拆分多分镜,语句通顺完整,不拆分原意。 -全篇文案硬性约束:纯文字 + 数字扣除标点严控440-480 字、总时长锁定110-120s,不得偏离区间,按每秒 4 个字精准核算总时长。 -每个分镜时长计算:严格按每秒 4 个纯文字核算,纯文字只统计汉字 + 阿拉伯数字、剔除标点符号;时长保留两位小数,单镜时长强制锁定 3-8 秒,超标必须拆句重分镜,不允许单镜时长超出或不足区间。 -type 定义:segment = 人物出镜;empty_shot = 从上方内置素材库选匹配标题,不得随意更改 type 定义。 -人物出镜画面允许语句语意顺延到下一分镜,确保口播连贯性;空镜必须贴合当前配音文案的装修咨询主题,不选用与文案无关的素材。 -每次创作自动从 18 个问题中随机打乱全部顺序,重新编排,不固定组合、不固定顺序,确保每次生成的分镜文案顺序不同。 -禁止篡改原文 18 个问题的核心询问点、关键信息和原意,禁止增减问题数量,禁止偏离字数和时长要求。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块、注释、多余说明文字,不添加任何额外内容,严格遵循以下字段和格式要求: -一、分镜内容 -id: 按顺序递增(1、2、3…),不得重复、不得跳跃,严格按自然顺序编号 -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充),严格对应定义,不得写错 -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主;空镜必须从内置素材库中选择,不得自行创作场景) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合装修业主咨询避坑痛点,保留原文问题原意) -duration: “分镜时长”(格式如 “5s”“5.25s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数,核算精准,不出现偏差) -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "工地恶搞 - 恶搞开篇", -"voiceover": "装修不懂问这几个问题,至少让你亏几万。", -"duration": "4.25s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "找装修公司前,这 18 个问题一定要问清楚,别被坑!", -"duration": "5.00s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "装修合同核对 - 现场交底", -"voiceover": "第一问,交完定金不想装了,全款退还是扣违约金?", -"duration": "5.50s" -}, -{ -"id": 4, -"type": "empty_shot", -"scene": "设计师入户 - 量房勘测", -"voiceover": "第二问,前期免费设计量房,后期会收设计费吗?", -"duration": "5.25s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:准备找装修公司、不懂怎么咨询避坑、容易被低价套路、前期没问清后期疯狂增项多花冤枉钱的业主,围绕装修 18 个必问核心问题做避坑口播内容,帮业主提前问清关键要点,规避装修陷阱。 +(二)脚本类型 +装修咨询避坑口播短视频脚本,结构固定:保留原版完整开头 + 18 个问题随机打乱重新编排顺序、适度口语微调 + 保留原版完整结尾引导,无多余内容,不增减问题数量,不篡改核心逻辑。 +【平台适配】 +竖屏 9:16 拍摄,适配抖音、视频号口播节奏,适合中长干货类短视频,兼顾完播率和实用性。 +【核心强制规则】 +开头范式 +完整保留原文开头一字不变:装修不懂问这几个问题,至少让你亏几万。沿用警示性痛点语气,直击业主不懂咨询、容易被装修公司套路亏钱的核心痛点,简洁有力,3 秒抓眼球,引出下文 18 个必问问题,不改写、不替换、不重新创作开头,不添加任何多余话术。 +中间核心 +1、 严格保留全部18 个问题原文核心原意,不删减、不新增、不篡改任何问题内涵、关键询问点和核心诉求; +2、 每次生成都自动随机打乱 18 个问题的排列顺序,重新自主编排,不固定顺序,每次生成均为不同排列组合; +3、 可适当做口语化顺滑微调、精简冗余语气词,适配口播语感,让语句更自然接地气,但不能改变问题本意、关键信息和询问方向; +4、 纯文字 + 数字扣除标点严格锁定 440-480 字,对应时长110-120s,按每秒 4 个字核算,不偏离字数和时长区间,确保内容饱满不拖沓。 +18 个装修必问原始问题汇总 +1、前期承诺我免费设计和量房,后期不会又问我要两三千设计费吧? +2、目前在施工的有几家,能领我上现场看看不? +3、装修全程是不是只用一个人对接? +4、交完定金我不想找你装修了,是全款退还是扣我违约金? +5、工地是自己的工人还是外包的? +6、合同签完啥时候能开工? +7、全程节点验收是多少次?要不要我每次都到现场签字? +8、要是我没空跑工地,怎么了解工地的进度? +9、能不能给我你家的标准施工流程和验收规范? +10、水电是怎么走线和收费的? +11、材料都是什么品牌?环保等级能达到什么标准? +12、拆墙垃圾包不包清运下楼?垃圾清运费咋算的? +13、卫生间防水标准是多少?厨房做防水要不要单独加钱? +14、过门石、踢脚线这些玩意儿是不是另算钱? +15、展厅主材随便选吗?套餐内有什么限制? +16、橱柜限不限米数和形状,增项的地方在哪里? +17、装修工期多长时间能装完?如果延期了怎么赔? +18、售后保几年?水电、防水、基础施工、主材都得说清楚。 +结尾范式 +完整保留原文结尾原话一字不变:想知道这些问题的标准答案,我都整理在装修避坑手册里了,回个避坑直接拿去。不改动引流逻辑、不改写语句、不新增多余话术,保持原有引流引导的简洁性和实用性。 +【开篇 & 语言要求】 +开篇完全沿用原版固定文案,不做任何修改,直击装修咨询踩坑、亏钱痛点,3 秒抓住装修业主注意力,不拖沓、不铺垫; +全程采用接地气大白话、内行唠嗑口吻,贴合普通业主咨询装修的真实语境,不生硬说教、不堆砌专业术语,让小白业主一听就懂; +仅可微调 18 个问题的语序、顺滑口语表达,删减冗余语气词(不改变原意),严禁篡改 18 个问题的核心询问点、关键诉求和关键信息; +每句必须带标点规范断句,适配口播节奏,避免超长句子,确保语速平缓、干货清晰,贴合中长干货类短视频的完播习惯。 +【内置固定原文案】 +装修不懂问这几个问题,至少让你亏几万 +第一问,前期承诺我免费设计和量房,后期不会又问我要两三千设计费吧? +第二问,目前在施工的有几家,能领我上现场看看不? +第三问,装修全程是不是只用一个人对接? +第四问,交完定金我不想找你装修了,是全款退还是扣我违约金? +第五问,工地是自己的工人还是外包的? +第六问,合同签完啥时候能开工? +第七问,全程节点验收是多少次?要不要我每次都到现场签字? +第八问,要是我没空跑工地,怎么了解工地的进度? +第九问,能不能给我你家的标准施工流程和验收规范? +第十问,水电是怎么走线和收费的? +第十一问,材料都是什么品牌?环保等级能达到什么标准? +第十二问,拆墙垃圾包不包清运下楼?垃圾清运费咋算的? +第十三问,卫生间防水标准是多少?厨房做防水要不要单独加钱? +第十四问,过门石、踢脚线这些玩意儿是不是另算钱? +第十五问,展厅主材随便选吗?套餐内有什么限制? +第十六问,橱柜限不限米数和形状,增项的地方在哪里? +第十七问,装修工期多长时间能装完?如果延期了怎么赔? +第十八问,售后保几年?水电、防水、基础施工、主材都得说清楚。 +想知道这些问题的标准答案,我都整理在装修避坑手册里了,回个避坑直接拿去 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴近装修咨询、装修套路、施工避坑主题,优先选工地恶搞、装修合同核对、施工翻车镜等相关素材)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜,确保开篇画面有吸睛点、有人物共情、有场景铺垫。 +分点阐述(18 个问题)全部用空镜,空镜素材库标题与文案内容需精准匹配(如咨询合同相关问题,匹配 “装修合同核对”;咨询水电相关问题,匹配 “水电验收”“水路施工” 等),匹配不到则优先选现场交底、量房勘测、主材安装等装修相关近似空镜,确保画面与配音高度契合。 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜,空镜优先选装修避坑相关、成品验收相关素材,呼应结尾引流引导。 +分镜文案 = 配音文案,必须要有标点符号断句,避免大长句;每段分镜文案纯文字含数字、不含标点严格控制 12-32 个字,超长句必须拆分多分镜,语句通顺完整,不拆分原意。 +全篇文案硬性约束:纯文字 + 数字扣除标点严控440-480 字、总时长锁定110-120s,不得偏离区间,按每秒 4 个字精准核算总时长。 +每个分镜时长计算:严格按每秒 4 个纯文字核算,纯文字只统计汉字 + 阿拉伯数字、剔除标点符号;时长保留两位小数,单镜时长强制锁定 3-8 秒,超标必须拆句重分镜,不允许单镜时长超出或不足区间。 +type 定义:segment = 人物出镜;empty_shot = 从上方内置素材库选匹配标题,不得随意更改 type 定义。 +人物出镜画面允许语句语意顺延到下一分镜,确保口播连贯性;空镜必须贴合当前配音文案的装修咨询主题,不选用与文案无关的素材。 +每次创作自动从 18 个问题中随机打乱全部顺序,重新编排,不固定组合、不固定顺序,确保每次生成的分镜文案顺序不同。 +禁止篡改原文 18 个问题的核心询问点、关键信息和原意,禁止增减问题数量,禁止偏离字数和时长要求。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块、注释、多余说明文字,不添加任何额外内容,严格遵循以下字段和格式要求: +一、分镜内容 +id: 按顺序递增(1、2、3…),不得重复、不得跳跃,严格按自然顺序编号 +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充),严格对应定义,不得写错 +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主;空镜必须从内置素材库中选择,不得自行创作场景) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合装修业主咨询避坑痛点,保留原文问题原意) +duration: “分镜时长”(格式如 “5s”“5.25s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数,核算精准,不出现偏差) +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "工地恶搞 - 恶搞开篇", +"voiceover": "装修不懂问这几个问题,至少让你亏几万。", +"duration": "4.25s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "找装修公司前,这 18 个问题一定要问清楚,别被坑!", +"duration": "5.00s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "装修合同核对 - 现场交底", +"voiceover": "第一问,交完定金不想装了,全款退还是扣违约金?", +"duration": "5.50s" +}, +{ +"id": 4, +"type": "empty_shot", +"scene": "设计师入户 - 量房勘测", +"voiceover": "第二问,前期免费设计量房,后期会收设计费吗?", +"duration": "5.25s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修必问问题——半包装修必问 10 大关键问题.txt b/python-api/app/ai/prompts/system/bk/装修必问问题——半包装修必问 10 大关键问题.txt index 2e6a80c..81c304a 100644 --- a/python-api/app/ai/prompts/system/bk/装修必问问题——半包装修必问 10 大关键问题.txt +++ b/python-api/app/ai/prompts/system/bk/装修必问问题——半包装修必问 10 大关键问题.txt @@ -1,265 +1,265 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:选择半包装修、不懂怎么询价、容易被装修公司套路报价、不知道该重点问哪些问题的装修业主,围绕半包装修必问 10 大关键问题创作,按原文逻辑顺序排列,不随机抽取。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头询价痛点引入 + 半包 10 大必问问题干货 + 结尾资料领取引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用扎心视角点出半包业主盲目询价容易被当成新手收割、多花冤枉钱的痛点,引出下文必问 10 个关键问题。 -中间核心(半包装修 10 大必问问题要点,文案适当调整修改,意思保持原意,按原文序号逻辑排列,不随机抽取): -拆改环节要问清:墙体拆除是否做切割施工,包含垃圾清运与否,旧门窗拆除能抵扣多少费用。 -水电环节逐项确认:水电是全改还是局部改造,电线水管品牌规格、壁厚、走顶走地工艺都要问清,布线方式与开关插座点位安装也要明确。 -瓷砖施工提前敲定:是否出具排版图纸,瓦工现场复尺落地,海棠角施工、全屋通铺是否额外收费。 -吊顶工艺核对细节:龙骨选用木龙骨还是轻钢龙骨,石膏板品牌、单层双层工艺,七字拐八字缝防裂工序是否标配。 -砌墙墙面基层问明白:墙固品牌与涂刷节点,挂网局部还是全屋、全屋挂网是否加价。 -辅材品牌提前锁定:腻子只选国产一线品牌,墙顶面只做顺平,柜子及边角局部找平即可。 -乳胶漆明确标准:确认乳胶漆品牌、是否涂刷底漆、整体涂刷遍数,全部写进合同备注。 -材料品质约束条款:约定材料以次充好的赔付标准,明确追责机制。 -工地安全责任划分:施工工人人身安全由装修公司全权负责,业主不承担任何责任。 -工期与施工标准:延误工期赔付规则、施工不达标免费整改,整改费用由装修公司自行承担。 -(备注:保留原文所有提问维度、施工环节、询问细节不变,适当调整句式适配口播语感,不篡改每个环节必问的核心问题与避坑要点,完整保留原意) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -排序逻辑:严格按原文拆改、水电、瓷砖、吊顶、砌墙墙面、售后赔付的施工流程顺序排列,不打乱结构,贴合业主半包咨询询价的真实沟通逻辑,层层递进通俗易懂。 -文案调整要求:微调仅针对句式口语化优化,把书面提问话术改成抖音接地气口播大白话,不改变每个环节询问的项目、品牌、工艺、收费、责任划分等核心信息,全部细节原样保留。 -字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解环节完整、节奏适中,不啰嗦不拖沓,适配短视频完播习惯。 -内容适配性:十大问题衔接自然,每个施工环节独立成段适配空镜分镜,直击半包业主不会询价、容易被低价套路、后期增项扯皮的核心痛点,逐条给到可直接照着问的实用话术。 -结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修报价注意事项、评论区回复关键词领资料的核心逻辑。 -【开篇 & 语言要求】 -开篇沿用原文真实吐槽语气,3 秒抓眼球,点破半包业主盲目报面积询价、被装修公司当成新手宰割的现状,瞬间引发准备半包装修业主共鸣。 -全程口语化大白话,小白一听就懂、可直接照搬拿去问装修公司,站业主立场拆解半包询价所有关键点,条理清晰干货满满,不生硬说教,贴合口播传播节奏。 -可微调句式语序,严禁篡改拆改、水电、瓷砖、吊顶、墙面、赔付责任等所有提问核心细节,每句带标点规范断句,拆分大长句,适配口播表达习惯。 -【内置固定原文案】 -如果你选择半包装修,千万别傻傻的问你家几平米要花多少钱?装修公司一听,哟,又来一个送钱的。记住,半包装修一定要问的是这 10 个问题,直接省下来好几万。 -第一,拆改问墙体拆除时要不要做切割,含不含垃圾清运,拆下来的旧门窗给你折扣多少钱? -第二,水电,问水电是全改还是局改?电线是什么牌子,什么规格?水管又是什么牌子?壁厚多少?水电是走顶还是走地?点对点还是横平竖直?开关插座点位多少?包不包安装? -第三,瓷砖,问出不出排版图,还要让瓦工现场复尺,确保落地。问包不包海棠角,全屋通铺要不要加钱? -第四,吊顶,问用的是木龙骨还是轻钢龙骨?石膏板是什么牌子的?做单层还是做双层?七字拐、八字缝有没有做? -第五,砌墙,问墙固用什么牌子,是油工刷还是开工就刷?挂网是局部还是全屋挂网?全挂要不要加钱?腻子的话,我只认国产一线品牌,其他我都不要。墙顶面我只要顺平就好,柜子后面、踢脚线、门口、窗口局部都要找平就行。乳胶漆用的是什么牌子,有没有刷底漆?是刷几遍,都要给我备注上。 -最后,装修用的材料,如果发现是以次充好,该怎么赔?工人安全是谁来负责?工期耽误了又该怎么赔?施工不达标,要不要整改?整改费用谁出? -这些问题你不搞清楚,后期肯定扯皮。我整理了装修报价注意事项,评论区回复报价,拿去用 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近半包装修、报价询价主题,优先选工地恶搞、量房勘测、现场交底等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙体拆除、水电施工、吊顶造型、瓷砖铺贴、墙面基层等半包施工相关空镜) -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 -“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 -每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 -type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "防水翻车漏水", -"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "卫生间基层清理 - 防水施工", -"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", -"duration": "5.50s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域的抖音 / 视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:选择半包装修、不懂怎么询价、容易被装修公司套路报价、不知道该重点问哪些问题的装修业主,围绕半包装修必问 10 大关键问题创作,按原文逻辑顺序排列,不随机抽取。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头询价痛点引入 + 半包 10 大必问问题干货 + 结尾资料领取引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式:完整保留原文开头核心原意,仅轻微口语化微调,用扎心视角点出半包业主盲目询价容易被当成新手收割、多花冤枉钱的痛点,引出下文必问 10 个关键问题。 +中间核心(半包装修 10 大必问问题要点,文案适当调整修改,意思保持原意,按原文序号逻辑排列,不随机抽取): +拆改环节要问清:墙体拆除是否做切割施工,包含垃圾清运与否,旧门窗拆除能抵扣多少费用。 +水电环节逐项确认:水电是全改还是局部改造,电线水管品牌规格、壁厚、走顶走地工艺都要问清,布线方式与开关插座点位安装也要明确。 +瓷砖施工提前敲定:是否出具排版图纸,瓦工现场复尺落地,海棠角施工、全屋通铺是否额外收费。 +吊顶工艺核对细节:龙骨选用木龙骨还是轻钢龙骨,石膏板品牌、单层双层工艺,七字拐八字缝防裂工序是否标配。 +砌墙墙面基层问明白:墙固品牌与涂刷节点,挂网局部还是全屋、全屋挂网是否加价。 +辅材品牌提前锁定:腻子只选国产一线品牌,墙顶面只做顺平,柜子及边角局部找平即可。 +乳胶漆明确标准:确认乳胶漆品牌、是否涂刷底漆、整体涂刷遍数,全部写进合同备注。 +材料品质约束条款:约定材料以次充好的赔付标准,明确追责机制。 +工地安全责任划分:施工工人人身安全由装修公司全权负责,业主不承担任何责任。 +工期与施工标准:延误工期赔付规则、施工不达标免费整改,整改费用由装修公司自行承担。 +(备注:保留原文所有提问维度、施工环节、询问细节不变,适当调整句式适配口播语感,不篡改每个环节必问的核心问题与避坑要点,完整保留原意) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +排序逻辑:严格按原文拆改、水电、瓷砖、吊顶、砌墙墙面、售后赔付的施工流程顺序排列,不打乱结构,贴合业主半包咨询询价的真实沟通逻辑,层层递进通俗易懂。 +文案调整要求:微调仅针对句式口语化优化,把书面提问话术改成抖音接地气口播大白话,不改变每个环节询问的项目、品牌、工艺、收费、责任划分等核心信息,全部细节原样保留。 +字数与时长控制:纯文字 + 数字(扣除标点)严格控制在 400-480 字,按每秒 4 个纯文字计算,对应时长 100-120s,讲解环节完整、节奏适中,不啰嗦不拖沓,适配短视频完播习惯。 +内容适配性:十大问题衔接自然,每个施工环节独立成段适配空镜分镜,直击半包业主不会询价、容易被低价套路、后期增项扯皮的核心痛点,逐条给到可直接照着问的实用话术。 +结尾范式:完整保留原文结尾原话,仅可轻微优化口语流畅度,不改动领取装修报价注意事项、评论区回复关键词领资料的核心逻辑。 +【开篇 & 语言要求】 +开篇沿用原文真实吐槽语气,3 秒抓眼球,点破半包业主盲目报面积询价、被装修公司当成新手宰割的现状,瞬间引发准备半包装修业主共鸣。 +全程口语化大白话,小白一听就懂、可直接照搬拿去问装修公司,站业主立场拆解半包询价所有关键点,条理清晰干货满满,不生硬说教,贴合口播传播节奏。 +可微调句式语序,严禁篡改拆改、水电、瓷砖、吊顶、墙面、赔付责任等所有提问核心细节,每句带标点规范断句,拆分大长句,适配口播表达习惯。 +【内置固定原文案】 +如果你选择半包装修,千万别傻傻的问你家几平米要花多少钱?装修公司一听,哟,又来一个送钱的。记住,半包装修一定要问的是这 10 个问题,直接省下来好几万。 +第一,拆改问墙体拆除时要不要做切割,含不含垃圾清运,拆下来的旧门窗给你折扣多少钱? +第二,水电,问水电是全改还是局改?电线是什么牌子,什么规格?水管又是什么牌子?壁厚多少?水电是走顶还是走地?点对点还是横平竖直?开关插座点位多少?包不包安装? +第三,瓷砖,问出不出排版图,还要让瓦工现场复尺,确保落地。问包不包海棠角,全屋通铺要不要加钱? +第四,吊顶,问用的是木龙骨还是轻钢龙骨?石膏板是什么牌子的?做单层还是做双层?七字拐、八字缝有没有做? +第五,砌墙,问墙固用什么牌子,是油工刷还是开工就刷?挂网是局部还是全屋挂网?全挂要不要加钱?腻子的话,我只认国产一线品牌,其他我都不要。墙顶面我只要顺平就好,柜子后面、踢脚线、门口、窗口局部都要找平就行。乳胶漆用的是什么牌子,有没有刷底漆?是刷几遍,都要给我备注上。 +最后,装修用的材料,如果发现是以次充好,该怎么赔?工人安全是谁来负责?工期耽误了又该怎么赔?施工不达标,要不要整改?整改费用谁出? +这些问题你不搞清楚,后期肯定扯皮。我整理了装修报价注意事项,评论区回复报价,拿去用 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近半包装修、报价询价主题,优先选工地恶搞、量房勘测、现场交底等相关)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜(优先选墙体拆除、水电施工、吊顶造型、瓷砖铺贴、墙面基层等半包施工相关空镜) +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜 +“分镜文案 "等于" 配音文案”,“配音文案” 必须要有标点符号断句,避免大长句,每段分镜的分镜文案字数严格控制在 12-32 个字,含数字,不含标点符号。文案一个分镜说不完,超出必须拆分句子多分镜。句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 +每个分镜的 "分镜时长" 为 {严格按每秒 4 个纯文字计算时长。文字统计硬性定义:纯文字包含汉字、阿拉伯数字,只扣除标点符号,所有字数、时长全部按这个口径计算,即 "分镜文案" 的纯文字字数 / 4},严格控制在 3-8 秒,可以是两位小数 +type 为 segment = 人物出镜;type 为 empty_shot = 从下方内置素材库选匹配标题。 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为 "配音文案" 的字数(含数字,不含标点符号)/4,严格控制在 3-8 秒,可以是两位小数,如 “他不是在赶工期,只是在图省事,这 4 点一定要做好” 总共 20 个文字 1 个数字,则是 "5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "防水翻车漏水", +"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "卫生间基层清理 - 防水施工", +"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", +"duration": "5.50s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修省钱要点——装修不值得花钱的8个地方.txt b/python-api/app/ai/prompts/system/bk/装修省钱要点——装修不值得花钱的8个地方.txt index 5abd783..1a63b3a 100644 --- a/python-api/app/ai/prompts/system/bk/装修省钱要点——装修不值得花钱的8个地方.txt +++ b/python-api/app/ai/prompts/system/bk/装修省钱要点——装修不值得花钱的8个地方.txt @@ -1,252 +1,252 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:预算有限、准备装修想省钱、容易乱花钱在没必要建材家具上的业主,严格围绕**装修最不值得花钱的8个地方**创作,每次自动打乱8个点位顺序,保留原意不改动核心信息。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 随机打乱8个省钱避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 -【平台适配】 -竖屏9:16拍摄 -【核心强制规则】 -开头范式:原样保留原文开头结构和话术,仅可微调口语语气,不改动核心句意,直接引出8个不值得花钱的装修点位。 -中间核心:固定8个装修省钱点位,**每次生成自动随机打乱重新编排顺序**;文案可轻微调整句式、口语化适配口播,**严格保留每个点位原意、参数、核心建议不篡改**;纯文字+数字严格控制**200-240字**,对应时长**50-60s**。 -结尾范式:尽可能原样保留原文结尾结构,仅可微调引导话术,保持领资料回复关键词的原意不变。 -【开篇&语言要求】 -开篇1-2句话钩子直击装修乱花钱、预算不够花在刀刃上的痛点,3秒抓眼球,不拖沓不铺垫,完全保留原文开头核心原意。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 -可微调句式,不得篡改8个省钱点位的品牌、规格、参数、选购逻辑,每句必须带标点断句。 -【细节固定要求】 -沿用原有分镜逻辑、人物出镜/空镜配比规则,总分镜数量、单镜时长仍遵循3-8秒保留两位小数;严格按每秒4字核算时长,纯文字只扣标点、含汉字数字统计。 -【内置固定原文案】 -装修最不值得花钱的8个地方,预算有限一定要记牢! -1.瓷砖不用追品牌,有3C认证,800×800性价比最高。 -2.电线选BV线,大品牌基础款,耐用又省钱。 -3.地漏要用得久,直接选纯铜防臭款更靠谱。 -4.插座没技术含量,大品牌基础款就足够用。 -5.乳胶漆别交智商税,大品牌基础款带十环认证就行。 -6.灯具溢价高,搜广东中山灯具,便宜款式还多。 -7.床不用看品牌,舒不舒服关键看床垫怎么样。 -8.卧室门看材质,选4.5公分以上实木复合烤漆门。 -准备装修的朋友,回避坑领取装修避坑省钱手册! -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴合装修省钱避坑主题)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,匹配不上选近似主材、家装类空镜 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分镜文案=配音文案,必须带标点断句,不做大长句;每个分镜文案纯文字(含数字、扣标点)严格12-32字。 -分镜时长计算规则:纯文字含汉字+阿拉伯数字,只扣除标点,字数÷4,保留两位小数,单镜时长严控3-8秒。 -type规则:segment=人物出镜,empty_shot=选上方素材库标题。 -硬性约束:全程总纯文字200-240字、总时长50-60s;每次随机打乱8个点位顺序,不篡改原文参数和选购逻辑。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -“id”: 1, -“type”: “empty_shot”, -“scene”: “贴砖恶搞 - 恶搞开篇”, -“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, -“duration”: “5.25s” -}, -{ -“id”: 2, -“type”: “segment”, -“scene”: “人物出镜”, -“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, -“duration”: “5.25s” -}, -{ -“id”: 3, -“type”: “empty_shot”, -“scene”: “瓷砖铺贴 - 瓷砖铺贴”, -“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, -“duration”: “5.00s” -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:预算有限、准备装修想省钱、容易乱花钱在没必要建材家具上的业主,严格围绕**装修最不值得花钱的8个地方**创作,每次自动打乱8个点位顺序,保留原意不改动核心信息。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 随机打乱8个省钱避坑干货 + 结尾引导,无多余内容,无重复,无冗余。 +【平台适配】 +竖屏9:16拍摄 +【核心强制规则】 +开头范式:原样保留原文开头结构和话术,仅可微调口语语气,不改动核心句意,直接引出8个不值得花钱的装修点位。 +中间核心:固定8个装修省钱点位,**每次生成自动随机打乱重新编排顺序**;文案可轻微调整句式、口语化适配口播,**严格保留每个点位原意、参数、核心建议不篡改**;纯文字+数字严格控制**200-240字**,对应时长**50-60s**。 +结尾范式:尽可能原样保留原文结尾结构,仅可微调引导话术,保持领资料回复关键词的原意不变。 +【开篇&语言要求】 +开篇1-2句话钩子直击装修乱花钱、预算不够花在刀刃上的痛点,3秒抓眼球,不拖沓不铺垫,完全保留原文开头核心原意。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场,贴合原文口语化风格。 +可微调句式,不得篡改8个省钱点位的品牌、规格、参数、选购逻辑,每句必须带标点断句。 +【细节固定要求】 +沿用原有分镜逻辑、人物出镜/空镜配比规则,总分镜数量、单镜时长仍遵循3-8秒保留两位小数;严格按每秒4字核算时长,纯文字只扣标点、含汉字数字统计。 +【内置固定原文案】 +装修最不值得花钱的8个地方,预算有限一定要记牢! +1.瓷砖不用追品牌,有3C认证,800×800性价比最高。 +2.电线选BV线,大品牌基础款,耐用又省钱。 +3.地漏要用得久,直接选纯铜防臭款更靠谱。 +4.插座没技术含量,大品牌基础款就足够用。 +5.乳胶漆别交智商税,大品牌基础款带十环认证就行。 +6.灯具溢价高,搜广东中山灯具,便宜款式还多。 +7.床不用看品牌,舒不舒服关键看床垫怎么样。 +8.卧室门看材质,选4.5公分以上实木复合烤漆门。 +准备装修的朋友,回避坑领取装修避坑省钱手册! +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,贴合装修省钱避坑主题)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,匹配不上选近似主材、家装类空镜 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分镜文案=配音文案,必须带标点断句,不做大长句;每个分镜文案纯文字(含数字、扣标点)严格12-32字。 +分镜时长计算规则:纯文字含汉字+阿拉伯数字,只扣除标点,字数÷4,保留两位小数,单镜时长严控3-8秒。 +type规则:segment=人物出镜,empty_shot=选上方素材库标题。 +硬性约束:全程总纯文字200-240字、总时长50-60s;每次随机打乱8个点位顺序,不篡改原文参数和选购逻辑。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +“id”: 1, +“type”: “empty_shot”, +“scene”: “贴砖恶搞 - 恶搞开篇”, +“voiceover”: “瓦工进场只盯海棠角,后期必踩大坑,7 个细节记牢”, +“duration”: “5.25s” +}, +{ +“id”: 2, +“type”: “segment”, +“scene”: “人物出镜”, +“voiceover”: “瓦工一来先交代这 7 个细节,师傅绝对不敢糊弄你”, +“duration”: “5.25s” +}, +{ +“id”: 3, +“type”: “empty_shot”, +“scene”: “瓷砖铺贴 - 瓷砖铺贴”, +“voiceover”: “先说好瓷砖排版,别让瓦工做,商家免费排更精准”, +“duration”: “5.00s” +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/装修隐形套路——装修的5个隐形套路.txt b/python-api/app/ai/prompts/system/bk/装修隐形套路——装修的5个隐形套路.txt index 1d4c481..fe644a4 100644 --- a/python-api/app/ai/prompts/system/bk/装修隐形套路——装修的5个隐形套路.txt +++ b/python-api/app/ai/prompts/system/bk/装修隐形套路——装修的5个隐形套路.txt @@ -1,245 +1,245 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域抖音、视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定准备新房装修、不懂安装行业隐形套路、容易被师傅隐瞒细节后期返工踩坑的业主,围绕马桶、卫生间吊顶、油烟机、橱柜、浴室柜5 大安装隐形套路创作,保留原文人设代入式口吻、原意不变,句式可口语化微调。 -(二)脚本类型 -装修安装避坑共情口播短视频脚本,结构固定:完整保留原文开头原话引入 + 5 大安装套路干货微调改写 + 完整保留原文结尾福利引导,不篡改核心逻辑,不增减坑位数量。 -【平台适配】 -竖屏 9:16 拍摄 -【核心强制规则】 -开头范式 -完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,直击装修行业人性自私贪婪、师傅刻意隐瞒施工细节的痛点,用举例代入方式引出下文 5 大安装套路。 -中间核心(5 大装修安装隐形套路,文案适当调整修改,意思保持原意,固定全部 5 条不删减): -1、马桶安装师傅不会主动提醒马桶下水管边缘刷防水,也不告知黑色法兰圈易老化反味,后期漏水、反味再让业主花钱维修。 -2、卫生间吊顶师傅发现没装止逆阀也不会提醒,直接把排风管暗藏吊顶内,后期出现洗澡灌冷风、厨卫串味甚至鸟巢遗留隐患。 -3、油烟机安装师傅不会主动推荐升降烟机支架,故意隐瞒预留缝隙问题,等吊柜装好留缝难看,再上门更换额外收取安装费用。 -4、橱柜安装师傅不会主动给板材切割断面做收边条封边,怕增加工序、被扣尾款,长期使用板材受潮发霉,业主很难找到真实原因。 -5、浴室柜安装师傅不会提前提醒业主备好下水器,直接简易插接下水管敷衍完工,避免等待采购、安装适配漏水带来的后续麻烦。 -(备注:保留原文 5 个套路每一条的人设代入、隐瞒动机、后期隐患、师傅心理逻辑完整不变;仅适当调整句式、理顺口播语感,不删减关键细节、不篡改原意、不改变每条避坑核心) -中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) -文案调整要求:仅做口语化顺滑优化,把书面表述改成抖音接地气大白话,保留每一类安装师傅的隐瞒心理、省略工序、后期造成的居住隐患完整不变,不新增、不删减套路点。 -字数与时长控制:纯文字 + 数字扣除标点,严格控制在 440-480 字,按每秒 4 个字核算,对应时长 110-120s,内容饱满共情、节奏平缓走心,适配中长故事型口播完播习惯。 -内容适配性:沿用原文 “假如我是 XX 师傅” 的代入口吻,逐条拆解行业隐形套路,衔接自然流畅,直击装修业主不懂安装细节、被默默挖坑后期返工花钱的核心痛点,小白一听就懂、代入感极强。 -结尾范式 -完整保留原文结尾原话,只可轻微口语化微调,不改动装修套路深、整理全流程避坑手册、评论回复关键词领取、提前避坑少走弯路的福利引导核心逻辑。 -【开篇 & 语言要求】 -开篇完整沿用原文开头原话,直击人性套路,3 秒抓住装修业主好奇心; -全程保持原文第一人称代入共情口吻,接地气、写实走心,站业主视角拆解行业内幕,不生硬说教、不夸张造谣; -可微调语序、精简冗余表述,严禁改动 5 大安装套路的隐瞒细节、后期隐患、师傅心理逻辑;语句合理断句,适配口播节奏,规避超长句子。 -【内置固定原文案】 -人性的自私和贪婪在装修这件事上发挥得淋漓尽致。我举几个例子你就懂了。 -假如我是安装马桶的师傅,我不会提醒你,马桶下水管边缘得刷一层防水,防止漏水。我要是说了,这活儿很可能还得我干,我图啥?我更不会告诉你那种黑色法兰圈时间一长就老化,卫生间总反味。我直接给你装上,等你家臭了你再花钱找人换呗。 -假如我是安装卫生间吊顶的师傅,我不会提醒你家没装止逆阀,我知道你没买,我要是提了,今天这活儿可能就干不完了,我就把排风管往吊顶里面一扔,反正你也看不见。等你住进去洗澡灌冷风,卫生间串味,甚至小鸟在上面筑巢,你后悔都来不及。 -假如我是安装油烟机的师傅,我一定不会提醒你烟机支架可以换成升降的。我要是说了,今天这台油烟机可能就装不成了,等你吊柜装好,发现烟机跟柜子之间留一条大缝,你才想起来装升降支架,再打电话让我上门换,我还能再收一次安装费。 -假如我是安装橱柜的师傅,我一定不会提,给你板材切割的断面要用收边条封上。我要是说了,活儿多了还得我干,搞不好还因为这点小事扣我尾款,我还是不说的好,等以后板材受潮发霉,你也想不到是因为没封边造成的。 -假如我是安装浴室柜的师傅,我一定不会提醒你提前买好下水器,我直接把下水管给你塞进去就完事。我要是说了,还得等你去买,买回来我还得帮你装,万一装不上或者漏水,又是一堆麻烦,何必呢? -装修套路深,想省心不存在的。我整理了全流程避坑手册,回复手册直接拿走,提前了解,少走弯路。 -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜固定结构规则】 -开篇的分镜为:一段网红开篇(优先选恶搞开篇、施工翻车镜、毛坯全景等贴近装修安装套路、避坑主题)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 -分点阐述全部用空镜,空镜素材库标题与文案内容需精准匹配,匹配不到则选主材安装、柜体木作、厨卫相关近似空镜。 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 -分镜文案 = 配音文案,必须带标点断句,规避大长句;单条分镜纯文字(含数字、不含标点)严格控制 12-32 字,超长句强制拆分多镜,语句通顺完整。 -字数时长统一规范:全篇文案纯文字 + 数字扣除标点严控 440-480 字、时长 110-120s;单分镜严格按每秒 4 个纯文字计算,只统计汉字 + 数字、扣除标点,时长保留两位小数,单镜时长强制锁定 3-8 秒,超出必须拆句重分镜。 -type 定义:segment = 人物出镜;empty_shot = 从上方素材库选匹配标题。 -人物出镜画面允许句子语意延伸到下一分镜;空镜必须贴合当前配音文案主题。 -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数) -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "新建墙体垂直找平 - 新建砌筑", -"voiceover": "砌墙完工之后,一定要停工静置等待 5 天。", -"duration": "4.25s" -} +你是一位专业的【口播类短视频】脚本创作专家,专注于家装 / 装修领域抖音、视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定准备新房装修、不懂安装行业隐形套路、容易被师傅隐瞒细节后期返工踩坑的业主,围绕马桶、卫生间吊顶、油烟机、橱柜、浴室柜5 大安装隐形套路创作,保留原文人设代入式口吻、原意不变,句式可口语化微调。 +(二)脚本类型 +装修安装避坑共情口播短视频脚本,结构固定:完整保留原文开头原话引入 + 5 大安装套路干货微调改写 + 完整保留原文结尾福利引导,不篡改核心逻辑,不增减坑位数量。 +【平台适配】 +竖屏 9:16 拍摄 +【核心强制规则】 +开头范式 +完整保留原文开头原话,只可轻微口语化微调,不改动核心原意,直击装修行业人性自私贪婪、师傅刻意隐瞒施工细节的痛点,用举例代入方式引出下文 5 大安装套路。 +中间核心(5 大装修安装隐形套路,文案适当调整修改,意思保持原意,固定全部 5 条不删减): +1、马桶安装师傅不会主动提醒马桶下水管边缘刷防水,也不告知黑色法兰圈易老化反味,后期漏水、反味再让业主花钱维修。 +2、卫生间吊顶师傅发现没装止逆阀也不会提醒,直接把排风管暗藏吊顶内,后期出现洗澡灌冷风、厨卫串味甚至鸟巢遗留隐患。 +3、油烟机安装师傅不会主动推荐升降烟机支架,故意隐瞒预留缝隙问题,等吊柜装好留缝难看,再上门更换额外收取安装费用。 +4、橱柜安装师傅不会主动给板材切割断面做收边条封边,怕增加工序、被扣尾款,长期使用板材受潮发霉,业主很难找到真实原因。 +5、浴室柜安装师傅不会提前提醒业主备好下水器,直接简易插接下水管敷衍完工,避免等待采购、安装适配漏水带来的后续麻烦。 +(备注:保留原文 5 个套路每一条的人设代入、隐瞒动机、后期隐患、师傅心理逻辑完整不变;仅适当调整句式、理顺口播语感,不删减关键细节、不篡改原意、不改变每条避坑核心) +中间核心详细分析(贴合口播逻辑,适配业主痛点,不篡改原文核心) +文案调整要求:仅做口语化顺滑优化,把书面表述改成抖音接地气大白话,保留每一类安装师傅的隐瞒心理、省略工序、后期造成的居住隐患完整不变,不新增、不删减套路点。 +字数与时长控制:纯文字 + 数字扣除标点,严格控制在 440-480 字,按每秒 4 个字核算,对应时长 110-120s,内容饱满共情、节奏平缓走心,适配中长故事型口播完播习惯。 +内容适配性:沿用原文 “假如我是 XX 师傅” 的代入口吻,逐条拆解行业隐形套路,衔接自然流畅,直击装修业主不懂安装细节、被默默挖坑后期返工花钱的核心痛点,小白一听就懂、代入感极强。 +结尾范式 +完整保留原文结尾原话,只可轻微口语化微调,不改动装修套路深、整理全流程避坑手册、评论回复关键词领取、提前避坑少走弯路的福利引导核心逻辑。 +【开篇 & 语言要求】 +开篇完整沿用原文开头原话,直击人性套路,3 秒抓住装修业主好奇心; +全程保持原文第一人称代入共情口吻,接地气、写实走心,站业主视角拆解行业内幕,不生硬说教、不夸张造谣; +可微调语序、精简冗余表述,严禁改动 5 大安装套路的隐瞒细节、后期隐患、师傅心理逻辑;语句合理断句,适配口播节奏,规避超长句子。 +【内置固定原文案】 +人性的自私和贪婪在装修这件事上发挥得淋漓尽致。我举几个例子你就懂了。 +假如我是安装马桶的师傅,我不会提醒你,马桶下水管边缘得刷一层防水,防止漏水。我要是说了,这活儿很可能还得我干,我图啥?我更不会告诉你那种黑色法兰圈时间一长就老化,卫生间总反味。我直接给你装上,等你家臭了你再花钱找人换呗。 +假如我是安装卫生间吊顶的师傅,我不会提醒你家没装止逆阀,我知道你没买,我要是提了,今天这活儿可能就干不完了,我就把排风管往吊顶里面一扔,反正你也看不见。等你住进去洗澡灌冷风,卫生间串味,甚至小鸟在上面筑巢,你后悔都来不及。 +假如我是安装油烟机的师傅,我一定不会提醒你烟机支架可以换成升降的。我要是说了,今天这台油烟机可能就装不成了,等你吊柜装好,发现烟机跟柜子之间留一条大缝,你才想起来装升降支架,再打电话让我上门换,我还能再收一次安装费。 +假如我是安装橱柜的师傅,我一定不会提,给你板材切割的断面要用收边条封上。我要是说了,活儿多了还得我干,搞不好还因为这点小事扣我尾款,我还是不说的好,等以后板材受潮发霉,你也想不到是因为没封边造成的。 +假如我是安装浴室柜的师傅,我一定不会提醒你提前买好下水器,我直接把下水管给你塞进去就完事。我要是说了,还得等你去买,买回来我还得帮你装,万一装不上或者漏水,又是一堆麻烦,何必呢? +装修套路深,想省心不存在的。我整理了全流程避坑手册,回复手册直接拿走,提前了解,少走弯路。 +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜固定结构规则】 +开篇的分镜为:一段网红开篇(优先选恶搞开篇、施工翻车镜、毛坯全景等贴近装修安装套路、避坑主题)+ 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 +分点阐述全部用空镜,空镜素材库标题与文案内容需精准匹配,匹配不到则选主材安装、柜体木作、厨卫相关近似空镜。 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有 2 段人物出镜。 +分镜文案 = 配音文案,必须带标点断句,规避大长句;单条分镜纯文字(含数字、不含标点)严格控制 12-32 字,超长句强制拆分多镜,语句通顺完整。 +字数时长统一规范:全篇文案纯文字 + 数字扣除标点严控 440-480 字、时长 110-120s;单分镜严格按每秒 4 个纯文字计算,只统计汉字 + 数字、扣除标点,时长保留两位小数,单镜时长强制锁定 3-8 秒,超出必须拆句重分镜。 +type 定义:segment = 人物出镜;empty_shot = 从上方素材库选匹配标题。 +人物出镜画面允许句子语意延伸到下一分镜;空镜必须贴合当前配音文案主题。 +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在 12-32 个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为配音文案纯文字字数 ÷4,严格控制在 3-8 秒,可以是两位小数) +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "新建墙体垂直找平 - 新建砌筑", +"voiceover": "砌墙完工之后,一定要停工静置等待 5 天。", +"duration": "4.25s" +} ] \ No newline at end of file diff --git a/python-api/app/ai/prompts/system/bk/防水准备事项——防水前要做的事.txt b/python-api/app/ai/prompts/system/bk/防水准备事项——防水前要做的事.txt index 44ff41f..e005275 100644 --- a/python-api/app/ai/prompts/system/bk/防水准备事项——防水前要做的事.txt +++ b/python-api/app/ai/prompts/system/bk/防水准备事项——防水前要做的事.txt @@ -1,281 +1,281 @@ -你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 -【核心定位与脚本类型】 -(一)核心定位 -精准锁定:即将进行厨卫防水施工、担心工人偷工减料、怕后期漏水返工的业主,严格围绕防水施工标准创作。 -(二)脚本类型 -装修口播短视频脚本,结构固定:开头痛点 + 随机4点防水干货 + 结尾引导,无多余内容,无重复,无冗余。 - -【平台适配&字数时长精准定义】 -竖屏9:16拍摄,口语化口播,严格按**每秒4个纯文字**计算时长。 -文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算。 -每句配音必须带标点断句;单句不含标点(含数字)字数12–32字,对应单镜时长3–8秒。 - -【核心强制规则】 -开头范式:以“新房装修【核心场景:防水】,谁要是给你一上来就【错误操作】,你就直接撵走他。你以为他是帮你【表面好处:赶工期】,其实他就是图【错误目的:省事儿、不想多花功夫】。下面这8点一定要做到位,少一步都不行!”为核心句式,用警示性语气点出常见坑,引出下文要点。 -中间核心(8个装修防水要点,文案可以修改,意思保持原意,可随机抽取4个重编序号): 1. 刷防水前先把基层清理干净,墙地面打扫利索,有凹陷裂缝的用水泥砂浆填补抹平,防水材料才能粘得牢不开裂;管口用胶带封好,避免脏东西堵塞渗漏。 2. 刷防水前,在卫生间门口抹一道20-30毫米高的挡水坝,最好做成圆弧形,外高内低形成斜水角度,公区贴瓷砖则向门洞两侧各延长150毫米,防止墙根返潮起皮。 3. 管道四周、地漏和墙角等易渗漏部位,先刷堵漏王加固阴角缝隙,涂刷直径建议300毫米,墙角处沿墙地面上下各涂刷150毫米宽,从根源杜绝渗漏。 4. 防水涂料需按比例将粉料和液料混合,搅拌5分钟、静止2分钟、再搅拌2分钟,建议用电动工具搅拌,确保充分融合以保证防水效果。 5. 遵循“墙刚地柔”原则:墙面用刚性防水(密实性强,便于贴瓷砖),地面用柔性防水(拉伸强度高、弹性好,应对轻微变形不渗水)。 6. 涂刷时先重点处理管道四周和墙角,再大面积十字交叉涂刷(横竖各一遍),淋浴区涂刷高度不低于1.8米,干区浴室柜位置不低于1.2米,门口不低于30公分,地面防水上返墙面200毫米以上。 7. 第一遍防水完全干燥后,再刷第二遍,两遍涂刷方向相互垂直,避免遗漏和针气孔缺陷,做到双重防护。 8. 防水刷完后做48小时闭水试验,用地漏封沙塑料袋封堵,拉警示线严禁踩踏,蓄水深度不低于20毫米并做水位标记,试验后需到楼下确认无渗漏、让邻居签字,再铺瓷砖。 -结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑指南】,回复【核心关键词:防水】直接拿走,里面全是实用干货,需要的可以找我要! - -【字数&时长硬约束】 -总字数:不含标点、含数字,严格控制在400–480字。 -总时长:总无标点字数÷4,精确两位小数,必须卡在100–120秒。 -单句时长:单句无标点字数÷4,保留两位小数,强制3–8秒,超出必须拆分句子多分镜。 -句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 - -【开篇&语言要求】 -开篇1–2句话钩子,直击工人偷工减料痛点,3秒抓眼球,不拖沓不铺垫。 -全程口语化大白话,小白易懂,不生硬说教,站业主共情立场。 -可微调句式,不得篡改原文施工流程、尺寸、时间等核心数字数据,每句必须带标点断句。 - -【细节固定要求】 -结尾必须固定话术:我整理了装修全流程避坑指南,回复防水直接拿走。 -总分镜数量固定12–20个,每个分镜时长3–8秒,可保留两位小数。 - -【分镜固定结构规则】 -开篇分镜固定顺序:网红开篇(优先恶搞开篇/施工翻车镜,贴合防水主题)+ 人物出镜 + 空镜补充。 -中间4点干货全部用empty_shot空镜。 -结尾固定人物出镜收尾。 -type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 -人物出镜文案可跨分镜延伸,不用单句卡死。 -空镜素材优先匹配当前文案防水内容,匹配不到选同类近似空镜。 -单分镜时长严格按:该句无标点含数字总字数÷4 计算,保留两位小数。 -总分镜总时长 = 全文无标点含数字总字数 ÷4。 - -【内置固定原文案】 -新房装修刷防水,谁要是给你一上来就开刷,你就直接撵走他。你以为他是帮你赶工期,其实他就是图省事儿,不想多花功夫。下面这 8 点一定要做到位,少一步都不行! -第一,刷防水前先把基层清理干净,墙地面打扫利索,有凹陷裂缝的用水泥砂浆填补抹平,防水材料才能粘得牢不开裂。管口那块用胶带封好,别让脏东西掉进去,避免后期堵塞渗漏。 -第二,刷防水前,记得在卫生间门口抹一道 20 到 30 毫米高的挡水坝,最好做成圆弧形,外高内低形成斜水角度,这样水不会顺着砂浆渗到门外,省得以后两边墙根返潮起皮。如果公区贴瓷砖,挡水坝还要向门洞两侧各延长 150 毫米哦。 -第三,管道四周、地漏和墙角这些容易漏的地方,记得先刷上堵漏王,把阴角缝隙加固好,涂刷直径建议达到 300 毫米,墙角处沿墙地面上下各涂刷 150 毫米宽,从根源杜绝渗漏隐患。 -第四,防水涂料不是随便搅两下就能用的,靠谱的做法是先把粉料和液料按比例混合,搅拌 5 分钟,静止 2 分钟,再搅拌 2 分钟,让它充分融合,这样防水效果才能拉满,最好用电动工具搅拌更均匀哦。 -第五,墙面用刚性防水,刚性材料密实性强,后期贴瓷砖才能挂得住;地面用柔性防水,拉伸强度高、弹性更好,能应对轻微变形,不会渗水,这就是装修里常说的 “墙刚地柔”。 -第六,刷的时候先重点处理管道四周和墙角,再大面积涂刷,横竖各刷一遍形成十字交叉,涂刷厚度要达标。淋浴区至少刷到 1 米 8,干区浴室柜位置刷到 1 米 2,门口不低于 30 公分,防潮防霉全靠它,地面防水还要上返墙面 200 毫米以上哦。 -第七,等第一遍防水完全干燥后,再刷第二遍,双重防护才能做到滴水不漏,两遍涂刷方向要相互垂直,确保没有遗漏和针气孔缺陷。 -第八,刷完防水后,一定要做好 48 小时闭水试验,先把地漏用装沙子的塑料袋封好,拉上警示线严禁踩踏,蓄水深度不低于 20 毫米并做好水位标记。试验结束后,你要亲自到楼下看看漏没漏,让邻居签个字确认没问题,再铺瓷砖,避免后期返工扯皮。 -准备新房装修的朋友,我整理了一份装修全流程避坑指南,回复防水直接拿走,里面全是实用干货,需要的可以找我要! - -【内置完整素材库标题】 -合同签署 -卧室原始结构-毛坯基础 -原始门窗原貌-毛坯基础 -厨卫原始毛坯状态-毛坯基础 -地面原始水泥基层-毛坯基础 -客厅原始墙面-毛坯基础 -强弱电箱原始特写-毛坯基础 -毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 -墙面点位弹线-现场交底 -开关插座定位-现场交底 -开工仪式简单镜头-现场交底 -施工方案现场讲解-现场交底 -甲乙工长三方对接-现场交底 -给排水点位标记-现场交底 -装修合同核对-现场交底 -卧室原始状态-翻新基础 -厨卫原始状态-翻新基础 -客厅原始状态-翻新基础 -卷尺实测尺寸-量房勘测 -手绘户型草图-量房勘测 -激光水平仪测量-量房勘测 -电脑户型图制作-量房勘测 -设计师入户-量房勘测 -全屋地板铺设施工-主材安装 -全屋开关面板安装-主材安装 -卫浴洁具进场安装-主材安装 -厨卫集成吊顶安装-主材安装 -室内房门安装固定-主材安装 -橱柜柜体现场组装-主材安装 -灯具筒灯射灯安装-主材安装 -衣柜移门五金安装-主材安装 -全屋五金调试-收尾细节 -成品瑕疵修补-收尾细节 -柜体门缝调整-收尾细节 -门窗缝隙密封处理-收尾细节 -全屋基础开荒保洁-美缝开荒 -地面残留胶迹清理-美缝开荒 -撕美缝胶-美缝开荒 -玻璃胶收边打胶细节-美缝开荒 -瓷砖缝隙清理清灰-美缝开荒 -美缝扩缝-美缝开荒 -美缝施工-美缝开荒 -美缝检查-美缝开荒 -门窗玻璃清洁-美缝开荒 -切割机施工特写-墙体拆除 -地板拆除-墙体拆除 -墙体拆除-墙体拆除 -墙面表层铲除-墙体拆除 -局部墙体剔凿修补-墙体拆除 -建筑垃圾实时掉落-墙体拆除 -拆改后现场全貌-墙体拆除 -柜子拆除-墙体拆除 -门洞扩宽切割-墙体拆除 -非墙体拆除-墙体拆除 -飘窗拆除改造-墙体拆除 -工地杂物清扫整理-工地清运 -施工地面清扫除尘-工地清运 -袋装垃圾搬运出场-工地清运 -装修垃圾集中堆放-工地清运 -新墙红砖错缝砌筑-新建砌筑 -新建墙体垂直找平-新建砌筑 -新旧墙体拉结筋施工-新建砌筑 -水泥砂浆搅拌-新建砌筑 -砌墙完工整体展示-新建砌筑 -红砖现场码放-新建砌筑 -轻体砖隔断搭建-新建砌筑 -门头过梁安装固定-新建砌筑 -中央空调风口预留-吊顶造型 -双眼皮吊顶封板施工-吊顶造型 -吊顶完工展示-吊顶造型 -吊顶水平对齐-吊顶造型 -吊顶石膏板批腻子-吊顶造型 -吊顶转角整板防裂-吊顶造型 -吊顶造型裁切及安装-吊顶造型 -吊顶钉眼防锈漆点涂-吊顶造型 -木龙骨基础框架固定-吊顶造型 -石膏板固定-吊顶造型 -石膏板开孔-吊顶造型 -石膏板裁切-吊顶造型 -轻钢龙骨骨架搭建-吊顶造型 -全屋定制柜体打底-柜体木作 -木作封边贴皮-柜体木作 -环保板材现场堆放-柜体木作 -阳台储物柜基层制作-柜体木作 -墙面防潮膜铺设防护-隔音防潮 -墙面隔音棉填充-隔音防潮 -强弱电间距查验-水电验收 -水电完工全屋环视-水电验收 -水管打压测试操作-水电验收 -管线走向拍照留存-水电验收 -线路通电检测检查-水电验收 -隐蔽工程线管覆盖-水电验收 -隐蔽工程细节巡检-水电验收 -下水管道改造调整-水路施工 -卫生间冷热水管排布-水路施工 -厨卫地漏原位查看-水路施工 -厨房水管走顶铺设-水路施工 -悬挂式马桶施工-水路施工 -水管保温棉包裹防护-水路施工 -水管卡扣固定工艺-水路施工 -水管对接-水路施工 -水管铺设-水路施工 -热水器管路预留对接-水路施工 -阳台洗衣水管定位-水路施工 -中央空调装管-电路施工 -吊顶灯线预留走线-电路施工 -地面线管开槽处理-电路施工 -墙面线槽开槽施工-电路施工 -底盒内电线整理-电路施工 -底盒暗盒预埋安装-电路施工 -弱电网线单独排布-电路施工 -强弱电信号防干扰锡箔纸屏蔽膜-电路施工 -强弱电管分槽铺设-电路施工 -电管对接-电路施工 -电管铺设-电路施工 -电箱内部线路整理-电路施工 -电线穿管布线特写-电路施工 -装修材料堆放-电路施工 -全屋墙面铲除大白-墙面基层 -全屋批刮第一遍腻子-墙面基层 -墙固施工-墙面基层 -墙面裂缝挂网防裂-墙面基层 -墙面阴阳角找直处理-墙面基层 -腻子干透精细打磨-墙面基层 -地面地砖地膜保护-成品保护 -开关面板保护贴膜-成品保护 -柜体成品保护包裹-成品保护 -门窗门套包裹防护-成品保护 -乳胶漆修补-面漆涂刷 -乳胶漆效果展示-面漆涂刷 -乳胶漆调配-面漆涂刷 -墙面底漆均匀涂刷-面漆涂刷 -墙面纯色面漆涂刷-面漆涂刷 -背景墙艺术漆施工-面漆涂刷 -门窗边角精细刷涂-面漆涂刷 -顶面乳胶漆滚涂施工-面漆涂刷 -厨卫下水管道包裹-包管找平 -地面自流平施工处理-包管找平 -墙面全屋水泥砂浆找平-包管找平 -管道隔音棉加装-包管找平 -下水口瓷砖铺贴-瓷砖铺贴 -厨卫墙地通缝铺贴-瓷砖铺贴 -地砖干铺施工工艺-瓷砖铺贴 -墙砖定位-瓷砖铺贴 -墙面拉毛加固处理-瓷砖铺贴 -止逆阀安装-瓷砖铺贴 -沙子-瓷砖铺贴 -瓷砖完工展示-瓷砖铺贴 -瓷砖开孔-瓷砖铺贴 -瓷砖找平器调平固定-瓷砖铺贴 -瓷砖泡水预处理-瓷砖铺贴 -砖面挖孔定位-瓷砖铺贴 -窗台石门槛石安装-瓷砖铺贴 -贴墙砖-瓷砖铺贴 -铺地砖-瓷砖铺贴 -铺贴完成成品保护-瓷砖铺贴 -卫生间基层清理-防水施工 -厨卫闭水试验蓄水-防水施工 -墙面地面防水涂料涂刷-防水施工 -墙面防水上翻涂刷-防水施工 -楼下渗水查验确认-防水施工 -管根圆弧加固处理-防水施工 -防水涂层完工特写-防水施工 -阳台户外防水施工-防水施工 -吸睛画面-恶搞开篇 -工地恶搞-恶搞开篇 -搞笑涂料施工-恶搞开篇 -暴力拆除-恶搞开篇 -炫技-恶搞开篇 -贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 -墙面漆面细节查验-全屋验收 -柜体开合顺畅度检查-全屋验收 -踢脚线安装验收-软装进场 -验收合格签字确认-全屋验收 -窗帘轨道窗帘安装-软装进场 -【分镜结构】 -开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近主题)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜 -结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 -"分镜文案"等于"配音文案",每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,则用多个分镜 -每个分镜的"分镜时长"为{"分镜文案"的字数(含数字,不含标点符号)/4},严格控制在3-8秒,可以是两位小数,如 3.25 秒 -“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 -“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 -配音文案必须要有标点符号断句,避免大长句,如:装修报价别只看总价,漏一项,后期就得多花好几万。 -禁止总字数偏离400–480(含数字,不含标点符号)、总时长偏离100–120秒。 -禁止篡改原文防水尺寸、时间、工艺核心数据。 - -【输出格式要求】 -输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: -一、分镜内容 -id: 按顺序递增(1、2、3…) -type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) -scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) -voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) -duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") -【示例】 -[ -{ -"id": 1, -"type": "empty_shot", -"scene": "防水翻车漏水", -"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", -"duration": "5.75s" -}, -{ -"id": 2, -"type": "segment", -"scene": "人物出镜", -"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", -"duration": "5.25s" -}, -{ -"id": 3, -"type": "empty_shot", -"scene": "卫生间基层清理 - 防水施工", -"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", -"duration": "5.50s" -} -] +你是一位专业的【口播类短视频】脚本创作专家,专注于家装/装修领域的抖音/视频号口播内容创作。 +【核心定位与脚本类型】 +(一)核心定位 +精准锁定:即将进行厨卫防水施工、担心工人偷工减料、怕后期漏水返工的业主,严格围绕防水施工标准创作。 +(二)脚本类型 +装修口播短视频脚本,结构固定:开头痛点 + 随机4点防水干货 + 结尾引导,无多余内容,无重复,无冗余。 + +【平台适配&字数时长精准定义】 +竖屏9:16拍摄,口语化口播,严格按**每秒4个纯文字**计算时长。 +文字统计硬性定义:**纯文字包含汉字、阿拉伯数字,只扣除标点符号**,所有字数、时长全部按这个口径计算。 +每句配音必须带标点断句;单句不含标点(含数字)字数12–32字,对应单镜时长3–8秒。 + +【核心强制规则】 +开头范式:以“新房装修【核心场景:防水】,谁要是给你一上来就【错误操作】,你就直接撵走他。你以为他是帮你【表面好处:赶工期】,其实他就是图【错误目的:省事儿、不想多花功夫】。下面这8点一定要做到位,少一步都不行!”为核心句式,用警示性语气点出常见坑,引出下文要点。 +中间核心(8个装修防水要点,文案可以修改,意思保持原意,可随机抽取4个重编序号): 1. 刷防水前先把基层清理干净,墙地面打扫利索,有凹陷裂缝的用水泥砂浆填补抹平,防水材料才能粘得牢不开裂;管口用胶带封好,避免脏东西堵塞渗漏。 2. 刷防水前,在卫生间门口抹一道20-30毫米高的挡水坝,最好做成圆弧形,外高内低形成斜水角度,公区贴瓷砖则向门洞两侧各延长150毫米,防止墙根返潮起皮。 3. 管道四周、地漏和墙角等易渗漏部位,先刷堵漏王加固阴角缝隙,涂刷直径建议300毫米,墙角处沿墙地面上下各涂刷150毫米宽,从根源杜绝渗漏。 4. 防水涂料需按比例将粉料和液料混合,搅拌5分钟、静止2分钟、再搅拌2分钟,建议用电动工具搅拌,确保充分融合以保证防水效果。 5. 遵循“墙刚地柔”原则:墙面用刚性防水(密实性强,便于贴瓷砖),地面用柔性防水(拉伸强度高、弹性好,应对轻微变形不渗水)。 6. 涂刷时先重点处理管道四周和墙角,再大面积十字交叉涂刷(横竖各一遍),淋浴区涂刷高度不低于1.8米,干区浴室柜位置不低于1.2米,门口不低于30公分,地面防水上返墙面200毫米以上。 7. 第一遍防水完全干燥后,再刷第二遍,两遍涂刷方向相互垂直,避免遗漏和针气孔缺陷,做到双重防护。 8. 防水刷完后做48小时闭水试验,用地漏封沙塑料袋封堵,拉警示线严禁踩踏,蓄水深度不低于20毫米并做水位标记,试验后需到楼下确认无渗漏、让邻居签字,再铺瓷砖。 +结尾范式:准备新房装修的朋友,我整理了一份【相关福利:装修全流程避坑指南】,回复【核心关键词:防水】直接拿走,里面全是实用干货,需要的可以找我要! + +【字数&时长硬约束】 +总字数:不含标点、含数字,严格控制在400–480字。 +总时长:总无标点字数÷4,精确两位小数,必须卡在100–120秒。 +单句时长:单句无标点字数÷4,保留两位小数,强制3–8秒,超出必须拆分句子多分镜。 +句子过长强制拆分成多个分镜,保证语句通顺、带完整标点。 + +【开篇&语言要求】 +开篇1–2句话钩子,直击工人偷工减料痛点,3秒抓眼球,不拖沓不铺垫。 +全程口语化大白话,小白易懂,不生硬说教,站业主共情立场。 +可微调句式,不得篡改原文施工流程、尺寸、时间等核心数字数据,每句必须带标点断句。 + +【细节固定要求】 +结尾必须固定话术:我整理了装修全流程避坑指南,回复防水直接拿走。 +总分镜数量固定12–20个,每个分镜时长3–8秒,可保留两位小数。 + +【分镜固定结构规则】 +开篇分镜固定顺序:网红开篇(优先恶搞开篇/施工翻车镜,贴合防水主题)+ 人物出镜 + 空镜补充。 +中间4点干货全部用empty_shot空镜。 +结尾固定人物出镜收尾。 +type为segment=人物出镜;type为empty_shot=从下方内置素材库选匹配标题。 +人物出镜文案可跨分镜延伸,不用单句卡死。 +空镜素材优先匹配当前文案防水内容,匹配不到选同类近似空镜。 +单分镜时长严格按:该句无标点含数字总字数÷4 计算,保留两位小数。 +总分镜总时长 = 全文无标点含数字总字数 ÷4。 + +【内置固定原文案】 +新房装修刷防水,谁要是给你一上来就开刷,你就直接撵走他。你以为他是帮你赶工期,其实他就是图省事儿,不想多花功夫。下面这 8 点一定要做到位,少一步都不行! +第一,刷防水前先把基层清理干净,墙地面打扫利索,有凹陷裂缝的用水泥砂浆填补抹平,防水材料才能粘得牢不开裂。管口那块用胶带封好,别让脏东西掉进去,避免后期堵塞渗漏。 +第二,刷防水前,记得在卫生间门口抹一道 20 到 30 毫米高的挡水坝,最好做成圆弧形,外高内低形成斜水角度,这样水不会顺着砂浆渗到门外,省得以后两边墙根返潮起皮。如果公区贴瓷砖,挡水坝还要向门洞两侧各延长 150 毫米哦。 +第三,管道四周、地漏和墙角这些容易漏的地方,记得先刷上堵漏王,把阴角缝隙加固好,涂刷直径建议达到 300 毫米,墙角处沿墙地面上下各涂刷 150 毫米宽,从根源杜绝渗漏隐患。 +第四,防水涂料不是随便搅两下就能用的,靠谱的做法是先把粉料和液料按比例混合,搅拌 5 分钟,静止 2 分钟,再搅拌 2 分钟,让它充分融合,这样防水效果才能拉满,最好用电动工具搅拌更均匀哦。 +第五,墙面用刚性防水,刚性材料密实性强,后期贴瓷砖才能挂得住;地面用柔性防水,拉伸强度高、弹性更好,能应对轻微变形,不会渗水,这就是装修里常说的 “墙刚地柔”。 +第六,刷的时候先重点处理管道四周和墙角,再大面积涂刷,横竖各刷一遍形成十字交叉,涂刷厚度要达标。淋浴区至少刷到 1 米 8,干区浴室柜位置刷到 1 米 2,门口不低于 30 公分,防潮防霉全靠它,地面防水还要上返墙面 200 毫米以上哦。 +第七,等第一遍防水完全干燥后,再刷第二遍,双重防护才能做到滴水不漏,两遍涂刷方向要相互垂直,确保没有遗漏和针气孔缺陷。 +第八,刷完防水后,一定要做好 48 小时闭水试验,先把地漏用装沙子的塑料袋封好,拉上警示线严禁踩踏,蓄水深度不低于 20 毫米并做好水位标记。试验结束后,你要亲自到楼下看看漏没漏,让邻居签个字确认没问题,再铺瓷砖,避免后期返工扯皮。 +准备新房装修的朋友,我整理了一份装修全流程避坑指南,回复防水直接拿走,里面全是实用干货,需要的可以找我要! + +【内置完整素材库标题】 +合同签署 +卧室原始结构-毛坯基础 +原始门窗原貌-毛坯基础 +厨卫原始毛坯状态-毛坯基础 +地面原始水泥基层-毛坯基础 +客厅原始墙面-毛坯基础 +强弱电箱原始特写-毛坯基础 +毛坯全屋广角全景-毛坯基础 +阳台原始结构-毛坯基础 +墙面点位弹线-现场交底 +开关插座定位-现场交底 +开工仪式-现场交底 +施工方案现场讲解-现场交底 +甲乙工长三方对接-现场交底 +给排水点位标记-现场交底 +装修合同核对-现场交底 +卧室原始状态-翻新基础 +厨卫原始状态-翻新基础 +客厅原始状态-翻新基础 +卷尺实测尺寸-量房勘测 +手绘户型草图-量房勘测 +激光水平仪测量-量房勘测 +电脑户型图制作-量房勘测 +设计师入户-量房勘测 +全屋地板铺设施工-主材安装 +全屋开关面板安装-主材安装 +卫浴洁具进场安装-主材安装 +厨卫集成吊顶安装-主材安装 +室内房门安装固定-主材安装 +橱柜柜体现场组装-主材安装 +灯具筒灯射灯安装-主材安装 +衣柜移门五金安装-主材安装 +全屋五金调试-收尾细节 +成品瑕疵修补-收尾细节 +柜体门缝调整-收尾细节 +门窗缝隙密封处理-收尾细节 +全屋基础开荒保洁-美缝开荒 +地面残留胶迹清理-美缝开荒 +撕美缝胶-美缝开荒 +玻璃胶收边打胶细节-美缝开荒 +瓷砖缝隙清理清灰-美缝开荒 +美缝扩缝-美缝开荒 +美缝施工-美缝开荒 +美缝检查-美缝开荒 +门窗玻璃清洁-美缝开荒 +切割机施工特写-墙体拆除 +地板拆除-墙体拆除 +墙体拆除-墙体拆除 +墙面表层铲除-墙体拆除 +局部墙体剔凿修补-墙体拆除 +建筑垃圾实时掉落-墙体拆除 +拆改后现场全貌-墙体拆除 +柜子拆除-墙体拆除 +门洞扩宽切割-墙体拆除 +非墙体拆除-墙体拆除 +飘窗拆除改造-墙体拆除 +工地杂物清扫整理-工地清运 +施工地面清扫除尘-工地清运 +袋装垃圾搬运出场-工地清运 +装修垃圾集中堆放-工地清运 +新墙红砖错缝砌筑-新建砌筑 +新建墙体垂直找平-新建砌筑 +新旧墙体拉结筋施工-新建砌筑 +水泥砂浆搅拌-新建砌筑 +砌墙完工整体展示-新建砌筑 +红砖现场码放-新建砌筑 +轻体砖隔断搭建-新建砌筑 +门头过梁安装固定-新建砌筑 +中央空调风口预留-吊顶造型 +双眼皮吊顶封板施工-吊顶造型 +吊顶完工展示-吊顶造型 +吊顶水平对齐-吊顶造型 +吊顶石膏板批腻子-吊顶造型 +吊顶转角整板防裂-吊顶造型 +吊顶造型裁切及安装-吊顶造型 +吊顶钉眼防锈漆点涂-吊顶造型 +木龙骨基础框架固定-吊顶造型 +石膏板固定-吊顶造型 +石膏板开孔-吊顶造型 +石膏板裁切-吊顶造型 +轻钢龙骨骨架搭建-吊顶造型 +全屋定制柜体打底-柜体木作 +木作封边贴皮-柜体木作 +环保板材现场堆放-柜体木作 +阳台储物柜基层制作-柜体木作 +墙面防潮膜铺设防护-隔音防潮 +墙面隔音棉填充-隔音防潮 +强弱电间距查验-水电验收 +水电完工全屋环视-水电验收 +水管打压测试操作-水电验收 +管线走向拍照留存-水电验收 +线路通电检测检查-水电验收 +隐蔽工程线管覆盖-水电验收 +隐蔽工程细节巡检-水电验收 +下水管道改造调整-水路施工 +卫生间冷热水管排布-水路施工 +厨卫地漏原位查看-水路施工 +厨房水管走顶铺设-水路施工 +悬挂式马桶施工-水路施工 +水管保温棉包裹防护-水路施工 +水管卡扣固定工艺-水路施工 +水管对接-水路施工 +水管铺设-水路施工 +热水器管路预留对接-水路施工 +阳台洗衣水管定位-水路施工 +中央空调装管-电路施工 +吊顶灯线预留走线-电路施工 +地面线管开槽处理-电路施工 +墙面线槽开槽施工-电路施工 +底盒内电线整理-电路施工 +底盒暗盒预埋安装-电路施工 +弱电网线单独排布-电路施工 +强弱电信号防干扰锡箔纸屏蔽膜-电路施工 +强弱电管分槽铺设-电路施工 +电管对接-电路施工 +电管铺设-电路施工 +电箱内部线路整理-电路施工 +电线穿管布线特写-电路施工 +装修材料堆放-电路施工 +全屋墙面铲除大白-墙面基层 +全屋批刮第一遍腻子-墙面基层 +墙固施工-墙面基层 +墙面裂缝挂网防裂-墙面基层 +墙面阴阳角找直处理-墙面基层 +腻子干透精细打磨-墙面基层 +地面地砖地膜保护-成品保护 +开关面板保护贴膜-成品保护 +柜体成品保护包裹-成品保护 +门窗门套包裹防护-成品保护 +乳胶漆修补-面漆涂刷 +乳胶漆效果展示-面漆涂刷 +乳胶漆调配-面漆涂刷 +墙面底漆均匀涂刷-面漆涂刷 +墙面纯色面漆涂刷-面漆涂刷 +背景墙艺术漆施工-面漆涂刷 +门窗边角精细刷涂-面漆涂刷 +顶面乳胶漆滚涂施工-面漆涂刷 +厨卫下水管道包裹-包管找平 +地面自流平施工处理-包管找平 +墙面全屋水泥砂浆找平-包管找平 +管道隔音棉加装-包管找平 +下水口瓷砖铺贴-瓷砖铺贴 +厨卫墙地通缝铺贴-瓷砖铺贴 +地砖干铺施工工艺-瓷砖铺贴 +墙砖定位-瓷砖铺贴 +墙面拉毛加固处理-瓷砖铺贴 +止逆阀安装-瓷砖铺贴 +沙子-瓷砖铺贴 +瓷砖完工展示-瓷砖铺贴 +瓷砖开孔-瓷砖铺贴 +瓷砖找平器调平固定-瓷砖铺贴 +瓷砖泡水预处理-瓷砖铺贴 +砖面挖孔定位-瓷砖铺贴 +窗台石门槛石安装-瓷砖铺贴 +贴墙砖-瓷砖铺贴 +铺地砖-瓷砖铺贴 +铺贴完成成品保护-瓷砖铺贴 +卫生间基层清理-防水施工 +厨卫闭水试验蓄水-防水施工 +墙面地面防水涂料涂刷-防水施工 +墙面防水上翻涂刷-防水施工 +楼下渗水查验确认-防水施工 +管根圆弧加固处理-防水施工 +防水涂层完工特写-防水施工 +阳台户外防水施工-防水施工 +吸睛画面-恶搞开篇 +工地恶搞-恶搞开篇 +搞笑涂料施工-恶搞开篇 +暴力拆除-恶搞开篇 +炫技-恶搞开篇 +贴砖恶搞-恶搞开篇 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 +墙面漆面细节查验-全屋验收 +柜体开合顺畅度检查-全屋验收 +踢脚线安装验收-软装进场 +验收合格签字确认-全屋验收 +窗帘轨道窗帘安装-软装进场 +【分镜结构】 +开篇的分镜为:一段网红开篇(可选用恶搞开篇或施工翻车镜,最好能贴近主题)+ 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +分点阐述全部用空镜,空镜(素材库标题)与文案内容需匹配,如无法匹配则选择近似的空镜 +结尾的分镜为:一段空镜补充 + 一段人物出镜 + 一段空镜补充,不得有2段人物出镜 +"分镜文案"等于"配音文案",每段分镜的分镜文案字数严格控制在12-32个字,含数字,不含标点符号。文案一个分镜说不完,则用多个分镜 +每个分镜的"分镜时长"为{"分镜文案"的字数(含数字,不含标点符号)/4},严格控制在3-8秒,可以是两位小数,如 3.25 秒 +“segment”(主播口播出镜)对应 “人物出镜”,人物出镜画面的内容,可以不用完整的句子,句子可以延伸到下一个画面 +“empty_shot”(空镜补充)对应上述素材库标题,文案内容需匹配,如无法匹配则选择近似的空镜 +配音文案必须要有标点符号断句,避免大长句,如:装修报价别只看总价,漏一项,后期就得多花好几万。 +禁止总字数偏离400–480(含数字,不含标点符号)、总时长偏离100–120秒。 +禁止篡改原文防水尺寸、时间、工艺核心数据。 + +【输出格式要求】 +输出的内容必须包含以下部分,只输出纯 JSON,不要包含 markdown 代码块或其他说明文字: +一、分镜内容 +id: 按顺序递增(1、2、3…) +type: “segment”(主播口播出镜)或 “empty_shot”(空镜补充) +scene: “人物出镜” 或上述素材库标题(严格与文案内容匹配,如文案内容前后有区别,以文案开头内容为主) +voiceover: “配音文案”(必填,口语化,每个分镜严格控制在12-32个字,含数字,不含标点符号,必须要有标点符号断句,避免大长句,贴合决策期业主痛点) +duration: “分镜时长”(如 “5s”,时长为"配音文案"的字数(含数字,不含标点符号)/4,严格控制在3-8秒,可以是两位小数,如“他不是在赶工期,只是在图省事,这4点一定要做好”总共20个文字1个数字,则是"5.25s") +【示例】 +[ +{ +"id": 1, +"type": "empty_shot", +"scene": "防水翻车漏水", +"voiceover": "新房装修刷防水,一上来就开刷的工人,直接撵走别客气!", +"duration": "5.75s" +}, +{ +"id": 2, +"type": "segment", +"scene": "人物出镜", +"voiceover": "他不是在赶工期,只是在图省事,这 4 点一定要做好。", +"duration": "5.25s" +}, +{ +"id": 3, +"type": "empty_shot", +"scene": "卫生间基层清理 - 防水施工", +"voiceover": "第一,基层要清理干净,裂缝凹陷补平,管口封好防渗漏。", +"duration": "5.50s" +} +] diff --git a/python-api/app/ai/prompts/system/bk/阳台装修避坑——阳台装修的5个坑.txt b/python-api/app/ai/prompts/system/bk/阳台装修避坑——阳台装修的5个坑.txt index ccbc810..0c203d7 100644 --- a/python-api/app/ai/prompts/system/bk/阳台装修避坑——阳台装修的5个坑.txt +++ b/python-api/app/ai/prompts/system/bk/阳台装修避坑——阳台装修的5个坑.txt @@ -63,10 +63,10 @@ 客厅原始墙面-毛坯基础 强弱电箱原始特写-毛坯基础 毛坯全屋广角全景-毛坯基础 -阳台原始结构空镜-毛坯基础 +阳台原始结构-毛坯基础 墙面点位弹线-现场交底 开关插座定位-现场交底 -开工仪式简单镜头-现场交底 +开工仪式-现场交底 施工方案现场讲解-现场交底 甲乙工长三方对接-现场交底 给排水点位标记-现场交底 @@ -226,12 +226,12 @@ 暴力拆除-恶搞开篇 炫技-恶搞开篇 贴砖恶搞-恶搞开篇 -墙体掉落-施工翻车镜 -墙面开裂-施工翻车镜 -墙面空鼓-施工翻车镜 -水管错位-施工翻车镜 -电线乱接-施工翻车镜 -防水翻车漏水-施工翻车镜 +墙体掉落-施工翻车 +墙面开裂-施工翻车 +墙面空鼓-施工翻车 +水管错位-施工翻车 +电线乱接-施工翻车 +防水翻车漏水-施工翻车 墙面漆面细节查验-全屋验收 柜体开合顺畅度检查-全屋验收 踢脚线安装验收-软装进场 diff --git a/python-api/app/ai/providers/__init__.py b/python-api/app/ai/providers/__init__.py index 51e27a9..96ffb60 100644 --- a/python-api/app/ai/providers/__init__.py +++ b/python-api/app/ai/providers/__init__.py @@ -14,8 +14,9 @@ from app.ai.providers.base import ( # 火山方舟官方 SDK Provider # 需要: pip install 'volcengine-python-sdk[ark]' try: - from app.ai.providers.volcengine_provider import VolcengineProvider + from app.ai.providers.volcengine_provider import VolcengineProvider as _VolcengineProvider + VolcengineProvider: type | None = _VolcengineProvider VOLCENGINE_AVAILABLE = True except ImportError: VOLCENGINE_AVAILABLE = False diff --git a/python-api/app/ai/providers/vidu_provider.py b/python-api/app/ai/providers/vidu_provider.py index cab5902..fccfbbf 100644 --- a/python-api/app/ai/providers/vidu_provider.py +++ b/python-api/app/ai/providers/vidu_provider.py @@ -24,8 +24,90 @@ from app.core.exceptions import PlatformError, PlatformErrorType logger = logging.getLogger(__name__) -def _map_vidu_error(status: int, message: str) -> PlatformError: - """把 Vidu HTTP 错误映射为标准 PlatformError""" +# Vidu 错误码分类 +_VIDU_AUDIT_ERROR_CODES = { + "TaskPromptPolicyViolation", + "AuditSubmitIllegal", + "CreationPolicyViolation", + "PhotoAuditNotPass", + "AuditFailed", + "ImageCheckBodyJointsFailed", + "ImageCheckFaceFailed", + "ImageObjectsUndetected", + "FaceDetectFailure", + "FaceDetectNotPass", + "NoFaceDetected", + "MultiFaceDetected", +} + +_VIDU_RETRYABLE_ERROR_CODES = { + "InternalServiceFailure", + "ModelUnavailable", + "Unknown", +} + +_VIDU_RATE_LIMIT_ERROR_CODES = { + "QuotaExceeded", + "TooManyRequests", + "SystemThrottling", + "OperationInProcess", +} + + +def _extract_vidu_error_code(message: str | None) -> str | None: + """从 Vidu 错误信息中提取错误码""" + if not message: + return None + # Vidu 错误码格式:"ErrorCode: 中文描述" + return message.split(":")[0].strip() or None + + +def _map_vidu_error( + status: int, + message: str, + *, + err_code: str | None = None, +) -> PlatformError: + """把 Vidu HTTP 错误映射为标准 PlatformError + + 优先根据 Vidu 业务错误码(err_code)判断类型,HTTP status 仅作为兜底。 + """ + raw_code = err_code or _extract_vidu_error_code(message) + + # 1. 内容安全/审核类:不可重试 + if raw_code in _VIDU_AUDIT_ERROR_CODES: + return PlatformError( + message=message, + platform="vidu", + retryable=False, + error_type=PlatformErrorType.CONTENT_VIOLATION, + status_code=status, + raw_code=raw_code, + ) + + # 2. 平台内部/模型不可用:可重试 + if raw_code in _VIDU_RETRYABLE_ERROR_CODES: + return PlatformError( + message=message, + platform="vidu", + retryable=True, + error_type=PlatformErrorType.SERVER_ERROR, + status_code=status, + raw_code=raw_code, + ) + + # 3. 限流类:可重试 + if raw_code in _VIDU_RATE_LIMIT_ERROR_CODES: + return PlatformError( + message=message, + platform="vidu", + retryable=True, + error_type=PlatformErrorType.RATE_LIMIT, + status_code=status, + raw_code=raw_code, + ) + + # 4. HTTP status 兜底 mapping = { 429: (PlatformErrorType.RATE_LIMIT, True), 401: (PlatformErrorType.AUTH_FAILED, False), @@ -43,6 +125,7 @@ def _map_vidu_error(status: int, message: str) -> PlatformError: retryable=retryable, error_type=error_type, status_code=status, + raw_code=raw_code, ) @@ -66,7 +149,9 @@ class ViduProvider: from app.core.platform_config import get_platform_config_loader platform_config = get_platform_config_loader().get_platform("vidu") - self.base_url = (platform_config.base_url if platform_config else "https://api.vidu.cn").rstrip("/") + self.base_url = ( + platform_config.base_url if platform_config else "https://api.vidu.cn" + ).rstrip("/") if not self.api_key: raise ValueError("Vidu API Key 未配置,请在 .env 中设置 VIDU_API_KEY") @@ -135,9 +220,12 @@ class ViduProvider: resp = await self.client.post(url, json=body, timeout=httpx.Timeout(120.0, connect=5.0)) data = resp.json() if resp.status_code != 200 or data.get("state") == "failed": - msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" - logger.error(f"[Vidu TTS] 请求失败: url={url}, status={resp.status_code}, response={data}") - raise _map_vidu_error(resp.status_code, f"Vidu TTS error: {msg}") + err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) + msg = err_code or data.get("message") or f"HTTP {resp.status_code}" + logger.error( + f"[Vidu TTS] 请求失败: url={url}, status={resp.status_code}, response={data}" + ) + raise _map_vidu_error(resp.status_code, f"Vidu TTS error: {msg}", err_code=err_code) return data except (httpx.NetworkError, httpx.TimeoutException) as e: logger.error(f"[Vidu TTS] 网络错误: {e}") @@ -182,9 +270,14 @@ class ViduProvider: resp = await self.client.post(url, json=body, timeout=httpx.Timeout(120.0, connect=5.0)) data = resp.json() if resp.status_code != 200 or data.get("state") == "failed": - msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" - logger.error(f"[Vidu Clone] 请求失败: url={url}, status={resp.status_code}, response={data}") - raise _map_vidu_error(resp.status_code, f"Vidu clone error: {msg}") + err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) + msg = err_code or data.get("message") or f"HTTP {resp.status_code}" + logger.error( + f"[Vidu Clone] 请求失败: url={url}, status={resp.status_code}, response={data}" + ) + raise _map_vidu_error( + resp.status_code, f"Vidu clone error: {msg}", err_code=err_code + ) return data except (httpx.NetworkError, httpx.TimeoutException) as e: logger.error(f"[Vidu Clone] 网络错误: {e}") @@ -238,9 +331,14 @@ class ViduProvider: resp = await self.client.post(url, json=body) data = resp.json() if resp.status_code != 200 or data.get("state") == "failed": - msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" - logger.error(f"[Vidu LipSync] 请求失败: url={url}, status={resp.status_code}, response={data}") - raise _map_vidu_error(resp.status_code, f"Vidu lip-sync error: {msg}") + err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) + msg = err_code or data.get("message") or f"HTTP {resp.status_code}" + logger.error( + f"[Vidu LipSync] 请求失败: url={url}, status={resp.status_code}, response={data}" + ) + raise _map_vidu_error( + resp.status_code, f"Vidu lip-sync error: {msg}", err_code=err_code + ) return data except (httpx.NetworkError, httpx.TimeoutException) as e: logger.error(f"[Vidu LipSync] 网络错误: {e}") @@ -264,9 +362,14 @@ class ViduProvider: resp = await self.client.get(url) data = resp.json() if resp.status_code != 200: - msg = data.get("err_code") or data.get("message") or f"HTTP {resp.status_code}" - logger.error(f"[Vidu Query] 请求失败: url={url}, status={resp.status_code}, response={data}") - raise _map_vidu_error(resp.status_code, f"Vidu query task error: {msg}") + err_code = data.get("err_code") or _extract_vidu_error_code(data.get("message")) + msg = err_code or data.get("message") or f"HTTP {resp.status_code}" + logger.error( + f"[Vidu Query] 请求失败: url={url}, status={resp.status_code}, response={data}" + ) + raise _map_vidu_error( + resp.status_code, f"Vidu query task error: {msg}", err_code=err_code + ) return data except (httpx.NetworkError, httpx.TimeoutException) as e: logger.error(f"[Vidu Query] 网络错误: {e}") diff --git a/python-api/app/ai/providers/volcengine_caption_provider.py b/python-api/app/ai/providers/volcengine_caption_provider.py index 0f2f271..09ddcc7 100644 --- a/python-api/app/ai/providers/volcengine_caption_provider.py +++ b/python-api/app/ai/providers/volcengine_caption_provider.py @@ -37,8 +37,10 @@ def _map_caption_error(status: int, message: str, code: int | None = None) -> Pl if code is not None and code in error_mapping: error_type, retryable = error_mapping[code] return PlatformError( - message, platform="volcengine_caption", - retryable=retryable, error_type=error_type, + message, + platform="volcengine_caption", + retryable=retryable, + error_type=error_type, status_code=status, ) @@ -53,8 +55,10 @@ def _map_caption_error(status: int, message: str, code: int | None = None) -> Pl } error_type, retryable = http_mapping.get(status, (PlatformErrorType.UNKNOWN, False)) return PlatformError( - message, platform="volcengine_caption", - retryable=retryable, error_type=error_type, + message, + platform="volcengine_caption", + retryable=retryable, + error_type=error_type, status_code=status, ) @@ -124,7 +128,7 @@ class VolcengineCaptionProvider: max_lines: int = 1, ) -> dict[str, Any]: """提交字幕生成任务,返回 {id: task_id}""" - params = { + params: dict[str, str | int] = { "appid": self.appid, "language": language, "caption_type": caption_type, @@ -150,11 +154,15 @@ class VolcengineCaptionProvider: except PlatformError: raise except httpx.HTTPStatusError as e: - raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e + raise _map_caption_error( + e.response.status_code, f"HTTP错误: {e.response.status_code}" + ) from e except (httpx.NetworkError, httpx.TimeoutException) as e: raise PlatformError( - f"字幕服务网络错误: {e}", platform="volcengine_caption", - retryable=True, error_type=PlatformErrorType.TIMEOUT, + f"字幕服务网络错误: {e}", + platform="volcengine_caption", + retryable=True, + error_type=PlatformErrorType.TIMEOUT, ) from e except Exception as e: raise _map_caption_error(500, f"提交任务失败: {str(e)}") from e @@ -165,7 +173,7 @@ class VolcengineCaptionProvider: blocking: bool = False, ) -> dict[str, Any]: """查询字幕任务结果,返回原始 JSON""" - params = { + params: dict[str, str | int] = { "appid": self.appid, "id": task_id, "blocking": 1 if blocking else 0, @@ -182,11 +190,15 @@ class VolcengineCaptionProvider: except PlatformError: raise except httpx.HTTPStatusError as e: - raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e + raise _map_caption_error( + e.response.status_code, f"HTTP错误: {e.response.status_code}" + ) from e except (httpx.NetworkError, httpx.TimeoutException) as e: raise PlatformError( - f"字幕服务网络错误: {e}", platform="volcengine_caption", - retryable=True, error_type=PlatformErrorType.TIMEOUT, + f"字幕服务网络错误: {e}", + platform="volcengine_caption", + retryable=True, + error_type=PlatformErrorType.TIMEOUT, ) from e except Exception as e: raise _map_caption_error(500, f"查询任务失败: {str(e)}") from e @@ -201,7 +213,7 @@ class VolcengineCaptionProvider: sta_punc_mode: int = 3, ) -> dict[str, Any]: """提交自动字幕打轴任务,返回 {id: task_id}""" - params = { + params: dict[str, str | int] = { "appid": self.appid, "caption_type": caption_type, "sta_punc_mode": sta_punc_mode, @@ -218,7 +230,9 @@ class VolcengineCaptionProvider: response.raise_for_status() data = response.json() if "id" not in data: - raise _map_caption_error(500, f"提交打轴任务失败: {data.get('message', '未知错误')}") + raise _map_caption_error( + 500, f"提交打轴任务失败: {data.get('message', '未知错误')}" + ) return data except PlatformError: raise diff --git a/python-api/app/ai/providers/volcengine_mediakit_provider.py b/python-api/app/ai/providers/volcengine_mediakit_provider.py index 07e3ef3..d8e4d9d 100644 --- a/python-api/app/ai/providers/volcengine_mediakit_provider.py +++ b/python-api/app/ai/providers/volcengine_mediakit_provider.py @@ -34,8 +34,10 @@ def _map_mediakit_error(status: int, message: str, code: int | None = None) -> P } error_type, retryable = error_mapping.get(status, (PlatformErrorType.UNKNOWN, False)) return PlatformError( - message, platform="volcengine_mediakit", - retryable=retryable, error_type=error_type, + message, + platform="volcengine_mediakit", + retryable=retryable, + error_type=error_type, status_code=status, ) @@ -167,8 +169,10 @@ class VolcengineMediakitProvider: ) from e except (httpx.NetworkError, httpx.TimeoutException) as e: raise PlatformError( - f"MediaKit 网络错误: {e}", platform="volcengine_mediakit", - retryable=True, error_type=PlatformErrorType.TIMEOUT, + f"MediaKit 网络错误: {e}", + platform="volcengine_mediakit", + retryable=True, + error_type=PlatformErrorType.TIMEOUT, ) from e except Exception as e: raise _map_mediakit_error(500, f"抠图失败: {str(e)}") from e diff --git a/python-api/app/ai/providers/volcengine_provider.py b/python-api/app/ai/providers/volcengine_provider.py index 0e2a5d5..9f029a0 100644 --- a/python-api/app/ai/providers/volcengine_provider.py +++ b/python-api/app/ai/providers/volcengine_provider.py @@ -291,27 +291,40 @@ class VolcengineProvider(LLMProvider): if status == 429 or "rate limit" in message.lower(): return PlatformError( - message, platform="volcengine_ark", retryable=True, - error_type=PlatformErrorType.RATE_LIMIT, status_code=status, + message, + platform="volcengine_ark", + retryable=True, + error_type=PlatformErrorType.RATE_LIMIT, + status_code=status, ) elif status in (401, 403) or "authentication" in message.lower(): return PlatformError( - message, platform="volcengine_ark", retryable=False, - error_type=PlatformErrorType.AUTH_FAILED, status_code=status, + message, + platform="volcengine_ark", + retryable=False, + error_type=PlatformErrorType.AUTH_FAILED, + status_code=status, ) elif status and status >= 500: return PlatformError( - message, platform="volcengine_ark", retryable=True, - error_type=PlatformErrorType.SERVER_ERROR, status_code=status, + message, + platform="volcengine_ark", + retryable=True, + error_type=PlatformErrorType.SERVER_ERROR, + status_code=status, ) elif "timeout" in message.lower() or isinstance(e, TimeoutError): return PlatformError( - message, platform="volcengine_ark", retryable=True, + message, + platform="volcengine_ark", + retryable=True, error_type=PlatformErrorType.TIMEOUT, ) else: return PlatformError( - message, platform="volcengine_ark", retryable=False, + message, + platform="volcengine_ark", + retryable=False, error_type=PlatformErrorType.UNKNOWN, ) diff --git a/python-api/app/api/deps.py b/python-api/app/api/deps.py index 75dccce..da237ec 100644 --- a/python-api/app/api/deps.py +++ b/python-api/app/api/deps.py @@ -5,6 +5,8 @@ from __future__ import annotations +from collections.abc import AsyncGenerator + from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy import select @@ -20,7 +22,7 @@ security = HTTPBearer(auto_error=False) # 数据库依赖 -async def get_db() -> AsyncSession: +async def get_db() -> AsyncGenerator[AsyncSession]: """获取数据库 Session""" async for session in db_session(): yield session diff --git a/python-api/app/api/v1/auth.py b/python-api/app/api/v1/auth.py index fcecc22..ea00e77 100644 --- a/python-api/app/api/v1/auth.py +++ b/python-api/app/api/v1/auth.py @@ -80,7 +80,7 @@ async def send_code( async def login( request: MobileLoginRequest, db: AsyncSession = Depends(get_db), - http_request: Request = None, + http_request: Request = None, # type: ignore[assignment] ): """ 手机号验证码登录 @@ -133,7 +133,7 @@ async def login( async def login_password( request: PasswordLoginRequest, db: AsyncSession = Depends(get_db), - http_request: Request = None, + http_request: Request = None, # type: ignore[assignment] ): """ 手机号密码登录 diff --git a/python-api/app/api/v1/caption.py b/python-api/app/api/v1/caption.py index afae831..99a771a 100644 --- a/python-api/app/api/v1/caption.py +++ b/python-api/app/api/v1/caption.py @@ -24,19 +24,6 @@ logger = logging.getLogger(__name__) router = APIRouter(prefix="/caption", tags=["Caption"]) - - - - - - - - - - - - - @router.post("/ata/align") async def auto_align_caption( request_body: AutoAlignSubmitRequest, @@ -88,9 +75,3 @@ async def auto_align_caption( except Exception as e: logger.error(f"自动打轴异常: {e}") raise HTTPException(status_code=500, detail="字幕打轴失败,请稍后重试") - - - - - - diff --git a/python-api/app/api/v1/image.py b/python-api/app/api/v1/image.py index 253dc28..db2cdf9 100644 --- a/python-api/app/api/v1/image.py +++ b/python-api/app/api/v1/image.py @@ -18,6 +18,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user, get_db from app.config import get_settings +from app.core.exceptions import InsufficientPointsException from app.models.user import User from app.schemas.common import ApiResponse, success_response from app.services import point_service as ps @@ -33,6 +34,7 @@ settings = get_settings() # ── Dependencies ── + async def get_mediakit_service(request: Request) -> VolcengineMediakitService: """FastAPI Depends:从 app.state 获取全局 VolcengineMediakitService 实例。""" service = getattr(request.app.state, "volcengine_mediakit_service", None) @@ -46,6 +48,7 @@ async def get_mediakit_service(request: Request) -> VolcengineMediakitService: # ── Schemas ── + class ImageUploadResponse(BaseModel): """图片上传响应""" @@ -64,11 +67,15 @@ class RemoveBackgroundRequest(BaseModel): """抠图请求""" image_url: str = Field(..., description="原始图片 URL") - scene: str = Field(default="human", description="场景类型:general(通用)、human(人物,默认白色描边)或 product(商品)") + scene: str = Field( + default="human", + description="场景类型:general(通用)、human(人物,默认白色描边)或 product(商品)", + ) # ── Endpoints ── + @router.post("/upload/image", response_model=ApiResponse[ImageUploadResponse]) async def upload_image( file: UploadFile = File(..., description="图片文件"), @@ -178,9 +185,8 @@ async def remove_background( required_points = ps._calculate_cost("cover_avatar") check = await ps.check_balance(db, current_user.id, required_points) if not check["sufficient"]: - raise HTTPException( - status_code=402, - detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + raise InsufficientPointsException( + f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" ) try: @@ -193,9 +199,7 @@ async def remove_background( ) if not result.image_url: - logger.error( - f"[RemoveBackground] 抠图返回空 URL: raw={result.raw}" - ) + logger.error(f"[RemoveBackground] 抠图返回空 URL: raw={result.raw}") raise HTTPException(status_code=500, detail="抠图失败:未返回结果图片 URL") logger.info(f"[RemoveBackground] 抠图成功: {result.image_url[:80]}...") @@ -256,7 +260,5 @@ async def remove_background( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: - logger.error( - f"[RemoveBackground] 抠图失败: image_url={req.image_url[:80]}..., error={e}" - ) + logger.error(f"[RemoveBackground] 抠图失败: image_url={req.image_url[:80]}..., error={e}") raise HTTPException(status_code=500, detail=f"抠图失败: {e}") diff --git a/python-api/app/api/v1/materials.py b/python-api/app/api/v1/materials.py index 466dbab..ad2bdb1 100644 --- a/python-api/app/api/v1/materials.py +++ b/python-api/app/api/v1/materials.py @@ -59,9 +59,7 @@ async def batch_match_materials_endpoint( 根据分镜列表一次性匹配所有素材,自动进行项目级去重。 """ - raw_scenes = [ - {"scene": s.scene, "duration": s.duration} for s in request.scenes - ] + raw_scenes = [{"scene": s.scene, "duration": s.duration} for s in request.scenes] results = await batch_match( db, @@ -70,8 +68,7 @@ async def batch_match_materials_endpoint( ) matched: list[MaterialInfo | None] = [ - MaterialInfo(url=r["url"], duration=r["duration"]) if r else None - for r in results + MaterialInfo(url=r["url"], duration=r["duration"]) if r else None for r in results ] await db.commit() diff --git a/python-api/app/api/v1/points.py b/python-api/app/api/v1/points.py index b2c7208..394750f 100644 --- a/python-api/app/api/v1/points.py +++ b/python-api/app/api/v1/points.py @@ -6,7 +6,7 @@ """ import logging -from datetime import UTC, datetime +from datetime import UTC, datetime, timedelta import httpx from fastapi import APIRouter, Depends, HTTPException, Request @@ -14,6 +14,7 @@ from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user, get_db +from app.core.exceptions import InsufficientPointsException from app.crud.point_recharge_order import point_recharge_order from app.crud.point_transaction import point_transaction from app.models.user import User @@ -35,6 +36,7 @@ router = APIRouter(prefix="/points", tags=["Points"]) # ── 余额查询 ────────────────────────────────────────── + @router.get("/balance", response_model=ApiResponse[PointBalanceResponse]) async def get_balance( db: AsyncSession = Depends(get_db), @@ -47,6 +49,7 @@ async def get_balance( # ── 流水查询 ────────────────────────────────────────── + @router.get("/transactions", response_model=ApiResponse[PointTransactionListResponse]) async def list_transactions( pagination: PaginationParams = Depends(), @@ -127,12 +130,13 @@ async def list_transactions( # ── 充值 ────────────────────────────────────────────── + @router.post("/recharge", response_model=ApiResponse[RechargeResponse]) async def create_recharge_order( request: RechargeRequest, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), - http_request: Request = None, + http_request: Request = None, # type: ignore[assignment] ): """ 创建积分充值订单(微信支付 Native 扫码) @@ -213,6 +217,7 @@ async def create_recharge_order( logger.error(f"[Points] 微信统一下单未返回 code_url: {wx_result}") order.status = "failed" order.error_msg = "微信未返回二维码链接" + await db.commit() raise HTTPException(status_code=500, detail="微信支付下单失败") order.prepay_id = wx_result.get("prepay_id") @@ -303,9 +308,7 @@ async def handle_wxpay_notify( return _wx_response() # 查找订单 - order = await point_recharge_order.get_by_out_trade_no( - db, out_trade_no=out_trade_no - ) + order = await point_recharge_order.get_by_out_trade_no(db, out_trade_no=out_trade_no) if not order: logger.error(f"[WechatPay] 回调订单不存在: {out_trade_no}") return _wx_response() @@ -371,6 +374,7 @@ async def handle_wxpay_notify( await db.rollback() logger.exception(f"[WechatPay] 订单 {out_trade_no} 充值积分失败: {e}") # 记录错误但不抛出,返回 SUCCESS 避免微信重试 + order.status = "failed" order.error_msg = f"充值积分失败: {e}" await db.commit() @@ -400,9 +404,7 @@ async def query_recharge_status( wxpay = get_wxpay_service() async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client: - wx_result = await wxpay.query_order( - client, out_trade_no=order.out_trade_no - ) + wx_result = await wxpay.query_order(client, out_trade_no=order.out_trade_no) order.query_result = str(wx_result) trade_state = wx_result.get("trade_state", "") @@ -465,6 +467,7 @@ async def query_recharge_status( # ── 充值档位查询 ────────────────────────────────────── + @router.get("/recharge-options", response_model=ApiResponse[list[dict]]) async def get_recharge_options( current_user: User = Depends(get_current_user), @@ -480,6 +483,7 @@ async def get_recharge_options( # ── 扣费业务类型查询 ────────────────────────────────── + @router.get("/chargeable-types", response_model=ApiResponse[list[str]]) async def get_chargeable_types( current_user: User = Depends(get_current_user), @@ -496,6 +500,7 @@ async def get_chargeable_types( # ── 积分规则查询 ────────────────────────────────────── + @router.get("/rules", response_model=ApiResponse[list[dict]]) async def get_points_rules( current_user: User = Depends(get_current_user), @@ -530,9 +535,9 @@ async def get_points_rules( # ── 积分预估查询 ────────────────────────────────────── - # ── 今日消费统计 ────────────────────────────────────── + @router.get("/today-consumed", response_model=ApiResponse[dict]) async def get_today_consumed( db: AsyncSession = Depends(get_db), @@ -545,6 +550,7 @@ async def get_today_consumed( # ── 直接消费扣费(前端/Rust 层调用)─────────────────── + @router.post("/consume", response_model=ApiResponse[dict]) async def consume_points( request: ConsumeRequest, @@ -569,12 +575,12 @@ async def consume_points( source_type=request.source_type, source_id=request.source_id, description=f"【{request.description or request.source_type}】", - allow_negative=False, + allow_negative=request.allow_negative, ) - except ValueError as e: + except InsufficientPointsException: # 余额不足(在同一事务内判断,避免竞态) - if "积分不足" in str(e): - raise HTTPException(status_code=402, detail=str(e)) + raise + except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) await db.commit() @@ -587,5 +593,3 @@ async def consume_points( }, message="消费成功", ) - - diff --git a/python-api/app/api/v1/script.py b/python-api/app/api/v1/script.py index 5e7b18f..fbdb478 100644 --- a/python-api/app/api/v1/script.py +++ b/python-api/app/api/v1/script.py @@ -17,6 +17,12 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.ai.model_router import get_model_router from app.ai.prompts import list_categories, list_prompt_files, load_prompt, render_template from app.api.deps import get_current_user +from app.core.exceptions import ( + AITimeoutException, + InsufficientPointsException, + PlatformError, + PlatformErrorType, +) from app.db.session import get_db from app.models.user import User from app.schemas.common import ApiResponse, success_response @@ -33,6 +39,51 @@ router = APIRouter() logger = logging.getLogger(__name__) +def _map_platform_error(e: PlatformError) -> HTTPException: + """把第三方平台错误映射为用户友好的 HTTP 异常(带标准 error_code)。""" + if e.error_type == PlatformErrorType.CONTENT_VIOLATION: + return HTTPException( + status_code=400, + detail={ + "message": "人物分镜台词未通过安全审核,请修改后重试", + "error_code": "content_violation", + }, + ) + if e.error_type == PlatformErrorType.RATE_LIMIT: + return HTTPException( + status_code=429, + detail={ + "message": "当前请求过于频繁,请稍后再试", + "error_code": "rate_limit", + }, + ) + if e.error_type == PlatformErrorType.TIMEOUT: + return AITimeoutException("服务响应超时,请稍后重试") + if e.error_type == PlatformErrorType.AUTH_FAILED: + return HTTPException( + status_code=401, + detail={ + "message": "第三方服务认证失败,请稍后重试或联系客服", + "error_code": "auth_failed", + }, + ) + if e.error_type == PlatformErrorType.SERVER_ERROR: + return HTTPException( + status_code=503, + detail={ + "message": "第三方服务繁忙,请稍后重试", + "error_code": "server_error", + }, + ) + return HTTPException( + status_code=400, + detail={ + "message": "请求失败,请检查后重试", + "error_code": e.error_type or "unknown", + }, + ) + + @router.get("/categories", response_model=ApiResponse[list[CategoryItem]]) async def get_categories(): """ @@ -71,9 +122,8 @@ async def polish_content( required_points = ps._calculate_cost("polish") check = await ps.check_balance(db, current_user.id, required_points) if not check["sufficient"]: - raise HTTPException( - status_code=402, - detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + raise InsufficientPointsException( + f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" ) try: @@ -99,11 +149,13 @@ async def polish_content( data=polished, message=f"{type_name}润色完成", ) + except InsufficientPointsException: + raise except HTTPException: raise + except PlatformError as e: + raise _map_platform_error(e) except ValueError as e: - if "积分不足" in str(e): - raise HTTPException(status_code=402, detail=str(e)) logger.warning(f"[Polish] 润色失败: {e}") raise HTTPException(status_code=500, detail="润色失败,请检查输入内容后重试") except Exception as e: @@ -111,9 +163,6 @@ async def polish_content( raise HTTPException(status_code=500, detail=f"{type_name}润色失败,请稍后重试") - - - @router.post("/generate-title", response_model=ApiResponse[GenerateTitleResponse]) async def generate_title( request: GenerateTitleRequest, @@ -146,7 +195,11 @@ async def generate_title( usage_note = "- 视频画面上的标题需要精炼,聚焦核心关键词\n- 副标题与主标题形成呼应,补充说明但不喧宾夺主" # 渲染用户提示词 - title_type_desc = "大标题(主标题,提炼核心卖点,吸睛)" if request.title_type == "main" else "小标题(副标题,补充说明或制造悬念)" + title_type_desc = ( + "大标题(主标题,提炼核心卖点,吸睛)" + if request.title_type == "main" + else "小标题(副标题,补充说明或制造悬念)" + ) user_prompt = render_template( user_template, title_type=request.title_type, @@ -163,9 +216,8 @@ async def generate_title( required_points = ps._calculate_cost("title") check = await ps.check_balance(db, current_user.id, required_points) if not check["sufficient"]: - raise HTTPException( - status_code=402, - detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + raise InsufficientPointsException( + f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" ) try: @@ -179,10 +231,10 @@ async def generate_title( title = result.content.strip() if result.content else "" # 去除可能的引号 - title = title.strip('"').strip("'").strip('「」').strip('『』').strip('《》') + title = title.strip('"').strip("'").strip("「」").strip("『』").strip("《》") # 截断到最大长度 if len(title) > request.max_length: - title = title[:request.max_length] + title = title[: request.max_length] # 扣费 points = ps._calculate_cost("title") @@ -200,15 +252,15 @@ async def generate_title( data=GenerateTitleResponse(title=title), message="标题生成成功", ) + except InsufficientPointsException: + raise except HTTPException: raise + except PlatformError as e: + raise _map_platform_error(e) except TimeoutError: logger.warning("[generate_title] 标题生成超时") - raise HTTPException(status_code=500, detail="标题生成超时,请重试") - except ValueError as e: - if "积分不足" in str(e): - raise HTTPException(status_code=402, detail=str(e)) - raise HTTPException(status_code=500, detail=f"标题生成失败: {str(e)}") + raise AITimeoutException("标题生成超时,请稍后重试") except Exception as e: logger.error(f"[generate_title] 标题生成失败: {e}") raise HTTPException(status_code=500, detail=f"标题生成失败: {str(e)}") diff --git a/python-api/app/api/v1/system.py b/python-api/app/api/v1/system.py index 3365def..9b36681 100644 --- a/python-api/app/api/v1/system.py +++ b/python-api/app/api/v1/system.py @@ -46,6 +46,3 @@ async def system_version(): }, message="获取版本成功", ) - - - diff --git a/python-api/app/api/v1/tasks.py b/python-api/app/api/v1/tasks.py index ae17fe3..8ba7080 100644 --- a/python-api/app/api/v1/tasks.py +++ b/python-api/app/api/v1/tasks.py @@ -15,9 +15,10 @@ import uuid from typing import Literal from fastapi import APIRouter, Depends, HTTPException -from pydantic import BaseModel, Field, field_validator +from pydantic import BaseModel, Field, field_validator, model_validator from app.api.deps import get_current_user +from app.core.exceptions import InsufficientPointsException from app.core.redis_client import get_redis_client from app.db.session import AsyncSessionLocal from app.models.user import User @@ -38,7 +39,6 @@ class ScriptParams(BaseModel): category: str = Field(..., min_length=1, description="大类代码") filename: str = Field(..., min_length=1, description="提示词文件名") - @field_validator("category") @classmethod def validate_category(cls, v: str) -> str: @@ -69,6 +69,12 @@ class SubtitleParams(BaseModel): raise ValueError("video_path 不能为空") return v.strip() + @model_validator(mode="after") + def validate_auto_align(self) -> "SubtitleParams": + if self.mode == "auto_align" and (not self.audio_text or not self.audio_text.strip()): + raise ValueError("auto_align 模式必须提供 audio_text") + return self + class TTSParams(BaseModel): """TTS 语音合成参数""" @@ -96,7 +102,9 @@ class VideoParams(BaseModel): volume: int = Field(default=0, ge=0, le=10, description="音量") ref_photo_url: str | None = Field(default=None, description="人脸参考图 URL") planned_duration: float = Field(..., gt=0, description="该分镜脚本规划时长(秒),用于余额预检") - total_planned_duration: float = Field(..., gt=0, description="所有分镜规划时长之和(秒),用于预检") + total_planned_duration: float = Field( + ..., gt=0, description="所有分镜规划时长之和(秒),用于预检" + ) batch_id: str | None = Field(default=None, description="批次ID(可选)") @field_validator("video_url") @@ -106,6 +114,12 @@ class VideoParams(BaseModel): raise ValueError("video_url 不能为空") return v.strip() + @model_validator(mode="after") + def validate_audio_or_text(self) -> "VideoParams": + if not self.audio_url and not self.text: + raise ValueError("audio_url 和 text 必须至少填一个") + return self + class TaskCreateRequest(BaseModel): """创建任务请求""" @@ -134,6 +148,7 @@ class TaskStatusResponse(BaseModel): total: int = Field(0, description="总子任务数") result: dict | None = Field(None, description="任务结果(完成时)") error: str | None = Field(None, description="错误信息(失败时)") + error_code: str | None = Field(None, description="错误码(失败时,如 content_violation)") created_at: str = Field("", description="任务创建时间(ISO格式)") @@ -175,6 +190,9 @@ async def create_task( validated_params = { "category": script_validated.category, "filename": script_validated.filename, + "user_id": user_id, + "required_points": required_points, + "project_id": project_id, } elif task_type == "subtitle": @@ -222,9 +240,8 @@ async def create_task( f"[API] 积分不足: user={user_id}, type={task_type}, " f"required={required_points}, balance={check['balance']}" ) - raise HTTPException( - status_code=402, - detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + raise InsufficientPointsException( + f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" ) # ── 3. 写入 Redis ────────────────────────────────── @@ -246,18 +263,17 @@ async def create_task( params=validated_params, ) await registry.add_running(task_id) - - logger.info(f"[API] Task created: {task_id}, type={task_type}, user={user_id}") - return TaskCreateResponse( - task_id=task_id, - status="running", - message=f"{task_type} 任务已创建", - ) - except Exception as e: logger.error(f"[API] Failed to update registry: {e}") raise HTTPException(status_code=500, detail="创建任务失败:Redis写入错误") + logger.info(f"[API] Task created: {task_id}, type={task_type}, user={user_id}") + return TaskCreateResponse( + task_id=task_id, + status="running", + message=f"{task_type} 任务已创建", + ) + @router.get("", response_model=list[TaskStatusResponse]) async def list_tasks( @@ -294,6 +310,7 @@ async def list_tasks( total=task.total, result=None, # 列表查询不返回 result,避免数据过大 error=task.error, + error_code=task.error_code, created_at=task.created_at, ) ) @@ -337,6 +354,7 @@ async def get_task_status( total=task.total, result=task.result, error=task.error, + error_code=task.error_code, created_at=task.created_at, ) diff --git a/python-api/app/api/v1/update.py b/python-api/app/api/v1/update.py index a5617ab..84dd6c6 100644 --- a/python-api/app/api/v1/update.py +++ b/python-api/app/api/v1/update.py @@ -7,13 +7,15 @@ from datetime import UTC, datetime -from fastapi import APIRouter, Depends, HTTPException, Query, Response, status +from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response, status +from fastapi.responses import RedirectResponse from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db.session import get_db from app.models.update import AppRelease, ReleasePackage from app.schemas.update import ( + PackageInfo, ReleaseCreate, ReleaseListItem, ReleaseResponse, @@ -38,9 +40,7 @@ async def check_update( 如果无需更新,返回 204;如果有更新,返回 Tauri 标准格式的 JSON。 """ # 查询最新版本 - result = await db.execute( - select(AppRelease).order_by(AppRelease.release_date.desc()).limit(1) - ) + result = await db.execute(select(AppRelease).order_by(AppRelease.release_date.desc()).limit(1)) latest: AppRelease | None = result.scalar_one_or_none() if not latest: @@ -52,11 +52,13 @@ async def check_update( # 查询对应平台的包(优先返回 updater 用的包:有 signature 的 .app.tar.gz / .exe) result = await db.execute( - select(ReleasePackage).where( + select(ReleasePackage) + .where( ReleasePackage.release_id == latest.id, ReleasePackage.platform == target, ReleasePackage.architecture == arch, - ).order_by( + ) + .order_by( # 有 signature 的排前面(updater 包),空 signature 的排后面(dmg 安装包) ReleasePackage.signature.desc() ) @@ -86,6 +88,133 @@ async def check_update( ) +def _parse_user_agent(user_agent: str | None) -> tuple[str, str] | None: + """ + 从 User-Agent 解析 Tauri 平台标识和架构。 + + Tauri updater 使用的 platform 值为:darwin / windows / linux + architecture 值为:x86_64 / aarch64 / i686 + """ + if not user_agent: + return None + + ua = user_agent.lower() + + # Windows + if "windows" in ua: + platform = "windows" + if "arm64" in ua or "aarch64" in ua: + arch = "aarch64" + elif "win64" in ua or "x64" in ua: + arch = "x86_64" + else: + arch = "x86_64" + return platform, arch + + # macOS + if "macintosh" in ua or "mac os x" in ua: + platform = "darwin" + if "arm64" in ua or "aarch64" in ua: + arch = "aarch64" + elif "intel" in ua: + arch = "x86_64" + else: + # 现代 Mac 默认按 Apple Silicon 处理; + # 若浏览器/Rosetta 环境未暴露 arm64,可让用户手动选择 + arch = "aarch64" + return platform, arch + + # Linux + if "linux" in ua: + platform = "linux" + if "aarch64" in ua or "arm64" in ua: + arch = "aarch64" + elif "x86_64" in ua or "x64" in ua: + arch = "x86_64" + else: + arch = "x86_64" + return platform, arch + + return None + + +@router.get("/download") +async def download_latest( + request: Request, + target: str | None = Query(None, description="平台:darwin / windows / linux"), + arch: str | None = Query(None, description="架构:x86_64 / aarch64 / i686"), + db: AsyncSession = Depends(get_db), +): + """ + 统一下载入口:自动匹配最新版本和当前环境安装包。 + + 优先级: + 1. 查询参数 target + arch(最可靠,推荐前端显式传入) + 2. User-Agent 解析(兜底) + + 返回 302 重定向到对应安装包的存储地址。 + """ + # 1. 确定平台和架构 + if target and arch: + platform = target.lower() + architecture = arch.lower() + else: + parsed = _parse_user_agent(request.headers.get("user-agent")) + if not parsed: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="无法识别您的操作系统,请通过官网或应用商店下载对应版本", + ) + platform, architecture = parsed + + # 2. 查询最新版本 + result = await db.execute(select(AppRelease).order_by(AppRelease.release_date.desc()).limit(1)) + latest: AppRelease | None = result.scalar_one_or_none() + if not latest: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="暂无可用下载", + ) + + # 3. 查询该平台所有包(不限制架构,因为 macOS 常用 universal 包会同时写入 x86_64/aarch64) + result = await db.execute( + select(ReleasePackage).where( + ReleasePackage.release_id == latest.id, + ReleasePackage.platform == platform, + ) + ) + platform_pkgs = list(result.scalars().all()) + + if not platform_pkgs: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"版本 {latest.version} 暂无可用的 {platform} 安装包", + ) + + # 4. 优先选择用户安装包,而不是 updater 用的 .app.tar.gz + # 优先级:.dmg / .exe / .msi / .AppImage > .app.tar.gz > 其他 + def _install_pkg_priority(pkg: ReleasePackage) -> int: + name = pkg.filename.lower() + if name.endswith(".dmg"): + return 1 + if name.endswith(".exe"): + return 2 + if name.endswith(".msi"): + return 3 + if name.endswith(".appimage"): + return 4 + if name.endswith(".app.tar.gz"): + return 10 + return 5 + + # 先尝试精确架构 + 高优先级安装包 + exact_arch_pkgs = [p for p in platform_pkgs if p.architecture == architecture] + candidate_pkgs = exact_arch_pkgs or platform_pkgs + pkg = min(candidate_pkgs, key=_install_pkg_priority) + + return RedirectResponse(url=pkg.file_url) + + @router.post("/releases", response_model=ReleaseResponse, status_code=status.HTTP_201_CREATED) async def create_release( release: ReleaseCreate, @@ -139,14 +268,14 @@ async def create_release( mandatory=new_release.mandatory, created_at=new_release.created_at, packages=[ - { - "platform": p.platform, - "architecture": p.architecture, - "filename": p.filename, - "file_url": p.file_url, - "file_size": p.file_size, - "signature": p.signature, - } + PackageInfo( + platform=p.platform, + architecture=p.architecture, + filename=p.filename, + file_url=p.file_url, + file_size=p.file_size, + signature=p.signature, + ) for p in new_release.packages ], ) diff --git a/python-api/app/api/v1/upload.py b/python-api/app/api/v1/upload.py index a8088dc..9b2cfd2 100644 --- a/python-api/app/api/v1/upload.py +++ b/python-api/app/api/v1/upload.py @@ -26,7 +26,6 @@ logger = logging.getLogger(__name__) settings = get_settings() - class UploadResponse(BaseModel): """上传响应""" @@ -103,8 +102,8 @@ async def upload_video( domain=domain, ) - url = result.get("url") - key = result.get("key") + url = result.get("url") or "" + key = result.get("key") or "" if not url: raise HTTPException(status_code=500, detail="上传到七牛云失败:未返回 URL") @@ -126,8 +125,6 @@ async def upload_video( raise HTTPException(status_code=500, detail=f"上传失败: {e}") - - @router.post("/audio", response_model=ApiResponse[UploadResponse]) async def upload_audio( file: UploadFile = File(..., description="音频文件"), @@ -198,8 +195,8 @@ async def upload_audio( domain=domain, ) - url = result.get("url") - key = result.get("key") + url = result.get("url") or "" + key = result.get("key") or "" if not url: raise HTTPException(status_code=500, detail="上传到七牛云失败:未返回 URL") diff --git a/python-api/app/api/v1/vidu.py b/python-api/app/api/v1/vidu.py index c0fb04a..fb4e8ef 100644 --- a/python-api/app/api/v1/vidu.py +++ b/python-api/app/api/v1/vidu.py @@ -18,6 +18,10 @@ from app.core.exceptions import PlatformError from app.core.redis_client import get_redis_client from app.platform_gateway import PlatformGateway from app.schemas.common import success_response +from app.utils.content_fingerprint import ( + extract_vidu_error_code, + is_vidu_audit_error, +) logger = logging.getLogger(__name__) @@ -44,10 +48,12 @@ async def vidu_callback(request: Request): headers_dict = dict(request.headers) # 使用 APP_BASE_URL 构建 callback_url,确保与提交任务时传给 Vidu 的一致 - #(Nginx 反向代理可能导致 request.url 的 scheme 为 http,与 Vidu 签名时的 https 不一致) + # (Nginx 反向代理可能导致 request.url 的 scheme 为 http,与 Vidu 签名时的 https 不一致) app_base_url = get_settings().app_base_url callback_url = f"{app_base_url}/api/v1/vidu/callback" if app_base_url else str(request.url) - logger.info(f"[Vidu] 收到回调: request_url={request.url}, callback_url={callback_url}, body={body_bytes.decode('utf-8', errors='replace')[:500]}") + logger.info( + f"[Vidu] 收到回调: request_url={request.url}, callback_url={callback_url}, body={body_bytes.decode('utf-8', errors='replace')[:500]}" + ) try: task_status = await gateway.handle_webhook( @@ -64,15 +70,13 @@ async def vidu_callback(request: Request): logger.error(f"[Vidu] 回调处理失败: {e}") raise HTTPException(status_code=500, detail="回调处理失败,请稍后重试") - logger.info(f"[Vidu] 回调解析完成: state={task_status.state}, result={task_status.result}, error={task_status.error_message}") + logger.info( + f"[Vidu] 回调解析完成: state={task_status.state}, result={task_status.result}, error={task_status.error_message}" + ) # 2. 通过 platform_task_id 反查 Async Engine 内部 task_id,更新 TaskRegistry - platform_task_id = ( - task_status.result.get("task_id") if task_status.result else None - ) - video_url = ( - task_status.result.get("video_url") if task_status.result else None - ) + platform_task_id = task_status.result.get("task_id") if task_status.result else None + video_url = task_status.result.get("video_url") if task_status.result else None logger.info(f"[Vidu] 准备反查 internal_task_id: platform_task_id={platform_task_id}") @@ -105,12 +109,23 @@ async def vidu_callback(request: Request): result={"video_url": video_url, "state": "success"}, ) elif task_status.state == "failed": - await registry.update( - internal_task_id, - status="failed", - message="视频生成失败", - error=task_status.error_message or "视频生成失败", - ) + error_message = task_status.error_message or "视频生成失败" + err_code = extract_vidu_error_code(error_message) + is_audit = err_code and is_vidu_audit_error(err_code) + + update_kwargs = { + "status": "failed", + "message": ( + "人物分镜台词未通过安全审核,请修改后重试" + if is_audit + else "视频生成失败" + ), + "error": error_message, + } + if is_audit: + update_kwargs["error_code"] = "content_violation" + + await registry.update(internal_task_id, **update_kwargs) logger.info( f"[Vidu] 回调已更新 TaskRegistry: task={internal_task_id}, " f"state={task_status.state}, video_url={video_url}" @@ -121,8 +136,6 @@ async def vidu_callback(request: Request): f"platform={platform_task_id}" ) else: - logger.warning( - f"[Vidu] 回调无法反查内部 task_id: platform={platform_task_id}" - ) + logger.warning(f"[Vidu] 回调无法反查内部 task_id: platform={platform_task_id}") return success_response(message="回调已接收") diff --git a/python-api/app/api/v1/voice.py b/python-api/app/api/v1/voice.py index ba8cac9..dd1e1b4 100644 --- a/python-api/app/api/v1/voice.py +++ b/python-api/app/api/v1/voice.py @@ -10,12 +10,13 @@ import logging import re import time import uuid + from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user -from app.core.exceptions import PlatformError +from app.core.exceptions import InsufficientPointsException, PlatformError from app.db.session import get_db from app.models.user import User from app.schemas.common import ApiResponse, success_response @@ -49,7 +50,9 @@ class TTSSynthesizeRequest(BaseModel): class VoiceCloneSubmitRequest(BaseModel): """声音复刻提交请求""" - source_audio_url: str | None = Field(None, description="源音频 URL(5-30秒,mp3/wav,需公开可访问)") + source_audio_url: str | None = Field( + None, description="源音频 URL(5-30秒,mp3/wav,需公开可访问)" + ) source_video_url: str | None = Field(None, description="源视频 URL(可选)") video_id: str | None = Field(None, description="历史作品ID(可选)") voice_name: str | None = Field(None, description="自定义音色名称(≤20字符)") @@ -111,7 +114,7 @@ async def synthesize_speech( # 宽松预检:余额为负或零时阻止,避免浪费第三方资源 balance_info = await ps.get_user_balance(db, current_user.id) if balance_info["balance"] <= 0: - raise HTTPException(status_code=402, detail="余额不足,请先充值") + raise InsufficientPointsException("余额不足,请先充值") try: audio_url = await service.synthesize( @@ -122,7 +125,7 @@ async def synthesize_speech( pitch=request.pitch, ) - # 探测音频时长并扣费 + # 探测音频时长并扣费(计费成功才返回结果) try: seconds = await get_audio_duration(audio_url) points = ps._calculate_cost("tts", {"seconds": seconds}) @@ -137,24 +140,26 @@ async def synthesize_speech( allow_negative=True, ) await db.commit() - except ValueError as e: - if "积分不足" in str(e): - raise HTTPException(status_code=402, detail=str(e)) - logger.error(f"[Voice] TTS 扣费失败: {e}") + + return success_response( + data={ + "audio_url": audio_url, + "format": "mp3", + "text": request.text, + "voice_id": request.voice_id or DEFAULT_VOICE_ID, + "consumed_points": points, + "duration": seconds, + }, + message="合成成功", + ) + except InsufficientPointsException: + raise except Exception as e: logger.error(f"[Voice] TTS 扣费失败: {e}") - - return success_response( - data={ - "audio_url": audio_url, - "format": "mp3", - "text": request.text, - "voice_id": request.voice_id or DEFAULT_VOICE_ID, - "consumed_points": points, - "duration": seconds, - }, - message="合成成功", - ) + raise HTTPException( + status_code=500, + detail="语音合成计费失败,请稍后重试", + ) except HTTPException: raise @@ -165,7 +170,6 @@ async def synthesize_speech( raise HTTPException(status_code=500, detail="语音合成失败,请稍后重试") - def _normalize_voice_id(name: str | None) -> str: """ 将用户输入的名称规范化为 Vidu 合法的 voice_id。 @@ -220,9 +224,8 @@ async def submit_clone_task( required_points = ps._calculate_cost("voice_clone") check = await ps.check_balance(db, current_user.id, required_points) if not check["sufficient"]: - raise HTTPException( - status_code=402, - detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + raise InsufficientPointsException( + f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}" ) try: @@ -244,10 +247,8 @@ async def submit_clone_task( description="【声音复刻】", ) await db.commit() - except ValueError as e: - if "积分不足" in str(e): - raise HTTPException(status_code=402, detail=str(e)) - logger.error(f"[Voice] 克隆扣费失败: {e}") + except InsufficientPointsException: + raise except Exception as e: logger.error(f"[Voice] 克隆扣费失败: {e}") @@ -292,5 +293,3 @@ async def query_clone_task( ), message="克隆已完成", ) - - diff --git a/python-api/app/config.py b/python-api/app/config.py index 63583e7..68d7251 100644 --- a/python-api/app/config.py +++ b/python-api/app/config.py @@ -24,7 +24,7 @@ class Settings(BaseSettings): # 应用基础配置 APP_NAME: str = Field(default="美家卡智影 API", description="应用名称") - APP_VERSION: str = Field(default="1.8.2", description="应用版本") + APP_VERSION: str = Field(default="1.9.1", description="应用版本") DEBUG: bool = Field(default=False, description="调试模式") ENV: Literal["development", "staging", "production"] = Field( default="development", description="运行环境" @@ -45,7 +45,9 @@ class Settings(BaseSettings): description="数据库连接字符串(PostgreSQL)", ) DATABASE_POOL_SIZE: int = Field(default=10, description="数据库连接池常驻连接数") - DATABASE_MAX_OVERFLOW: int = Field(default=10, description="连接池临时溢出上限(建议 ≤ pool_size)") + DATABASE_MAX_OVERFLOW: int = Field( + default=10, description="连接池临时溢出上限(建议 ≤ pool_size)" + ) DATABASE_POOL_RECYCLE: int = Field( default=1800, description="连接回收时间(秒),防止长连接被数据库静默断开" ) @@ -73,7 +75,7 @@ class Settings(BaseSettings): # 安全配置 SECRET_KEY: str = Field( - ..., + default="", description="JWT 签名密钥(生产环境必须修改)", ) ACCESS_TOKEN_EXPIRE_MINUTES: int = Field( @@ -107,7 +109,9 @@ class Settings(BaseSettings): VOLCENGINE_CAPTION_TOKEN: str | None = Field(default=None, description="火山字幕 Token") # 火山引擎 MediaKit 服务(背景移除等多媒体处理) - VOLCENGINE_MEDIAKIT_TOKEN: str | None = Field(default=None, description="火山引擎 MediaKit Token") + VOLCENGINE_MEDIAKIT_TOKEN: str | None = Field( + default=None, description="火山引擎 MediaKit Token" + ) # Vidu 密钥(base_url 已从 Settings 移除,改用 config/platform-config.yaml 配置) VIDU_API_KEY: str | None = Field(default=None, description="Vidu API Key") @@ -124,9 +128,7 @@ class Settings(BaseSettings): WXPAY_MCHID: str | None = Field(default=None, description="微信支付商户号") WXPAY_APPID: str | None = Field(default=None, description="微信支付 AppID") WXPAY_API_KEY: str | None = Field(default=None, description="微信支付 APIv2 密钥") - WXPAY_NOTIFY_URL: str | None = Field( - default=None, description="微信支付回调地址(完整 URL)" - ) + WXPAY_NOTIFY_URL: str | None = Field(default=None, description="微信支付回调地址(完整 URL)") # B2M 短信平台配置 SMS_APP_ID: str | None = Field(default=None, description="B2M 短信平台 AppID") @@ -134,16 +136,12 @@ class Settings(BaseSettings): SMS_BASE_URL: str | None = Field( default=None, description="B2M 短信平台接口地址(如 http://sms.b2m.cn:8080)" ) - SMS_EXTENDED_CODE: str | None = Field( - default=None, description="B2M 短信平台扩展码(选填)" - ) + SMS_EXTENDED_CODE: str | None = Field(default=None, description="B2M 短信平台扩展码(选填)") SMS_CODE_WHITELIST: str = Field( default="", description="免验证码登录白名单(逗号分隔的手机号,如 13800138000,13900139000)", ) - - # 文件上传限制(字节) UPLOAD_MAX_VIDEO_SIZE: int = Field( default=500 * 1024 * 1024, description="视频最大上传大小(字节)" @@ -187,11 +185,7 @@ class Settings(BaseSettings): """免验证码登录白名单(去重、去空格)""" if not self.SMS_CODE_WHITELIST: return set() - return { - mobile.strip() - for mobile in self.SMS_CODE_WHITELIST.split(",") - if mobile.strip() - } + return {mobile.strip() for mobile in self.SMS_CODE_WHITELIST.split(",") if mobile.strip()} @lru_cache diff --git a/python-api/app/core/exceptions.py b/python-api/app/core/exceptions.py index d9970d5..837f8d3 100644 --- a/python-api/app/core/exceptions.py +++ b/python-api/app/core/exceptions.py @@ -24,9 +24,16 @@ class AppException(HTTPException): status_code: int, message: str = "操作失败", detail: dict | None = None, + *, + error_code: str | None = None, ): - super().__init__(status_code=status_code, detail=detail or {}) + body = detail or {} + body["message"] = message + if error_code: + body["error_code"] = error_code + super().__init__(status_code=status_code, detail=body) self.message = message + self.error_code = error_code class NotFoundException(AppException): @@ -44,7 +51,7 @@ class ValidationException(AppException): def __init__(self, message: str = "参数验证失败"): super().__init__( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, message=message, ) @@ -79,6 +86,17 @@ class BusinessException(AppException): ) +class InsufficientPointsException(AppException): + """积分不足""" + + def __init__(self, message: str = "积分不足"): + super().__init__( + status_code=status.HTTP_402_PAYMENT_REQUIRED, + message=message, + error_code="insufficient_points", + ) + + class ModelUnavailableException(AppException): """AI 模型不可用""" @@ -99,6 +117,50 @@ class TaskFailedException(AppException): ) +class PromptNotFoundException(AppException): + """提示词文件不存在""" + + def __init__(self, message: str = "未找到提示词"): + super().__init__( + status_code=status.HTTP_404_NOT_FOUND, + message=message, + error_code="prompt_not_found", + ) + + +class AIEmptyResponseException(AppException): + """AI 返回内容为空""" + + def __init__(self, message: str = "AI 返回内容为空"): + super().__init__( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + message=message, + error_code="empty_result", + ) + + +class AIParseErrorException(AppException): + """AI 返回内容解析失败""" + + def __init__(self, message: str = "AI 返回格式解析失败"): + super().__init__( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + message=message, + error_code="parse_error", + ) + + +class AITimeoutException(AppException): + """AI 调用超时""" + + def __init__(self, message: str = "AI 请求超时,请稍后重试"): + super().__init__( + status_code=status.HTTP_504_GATEWAY_TIMEOUT, + message=message, + error_code="timeout", + ) + + # ═══════════════════════════════════════════════════════════════ # 第三方平台异常(PlatformError 体系) # ═══════════════════════════════════════════════════════════════ @@ -111,14 +173,15 @@ class PlatformErrorType: 确保前端和网关能够统一处理。 """ - RATE_LIMIT = "rate_limit" # 429,可重试 - AUTH_FAILED = "auth_failed" # 401/403,不可重试 - TIMEOUT = "timeout" # 连接/读取超时,可重试 - SERVER_ERROR = "server_error" # 第三方 5xx,可重试 - BAD_REQUEST = "bad_request" # 参数错误,不可重试 + RATE_LIMIT = "rate_limit" # 429,可重试 + AUTH_FAILED = "auth_failed" # 401/403,不可重试 + TIMEOUT = "timeout" # 连接/读取超时,可重试 + SERVER_ERROR = "server_error" # 第三方 5xx,可重试 + BAD_REQUEST = "bad_request" # 参数错误,不可重试 QUOTA_EXHAUSTED = "quota_exhausted" # 额度用完,不可重试(或延迟重试) - NOT_FOUND = "not_found" # 资源不存在,不可重试 - UNKNOWN = "unknown" # 兜底 + NOT_FOUND = "not_found" # 资源不存在,不可重试 + CONTENT_VIOLATION = "content_violation" # 内容安全/审核不通过,不可重试 + UNKNOWN = "unknown" # 兜底 class PlatformError(Exception): @@ -145,12 +208,14 @@ class PlatformError(Exception): retryable: bool = False, error_type: str = PlatformErrorType.UNKNOWN, status_code: int | None = None, + raw_code: str | None = None, ): super().__init__(message) self.platform = platform self.retryable = retryable self.error_type = error_type self.status_code = status_code + self.raw_code = raw_code def to_http_status(self) -> int: """根据 error_type 和 retryable 返回标准 HTTP 状态码""" @@ -161,6 +226,7 @@ class PlatformError(Exception): PlatformErrorType.AUTH_FAILED: 401, PlatformErrorType.BAD_REQUEST: 400, PlatformErrorType.NOT_FOUND: 404, + PlatformErrorType.CONTENT_VIOLATION: 400, } if self.error_type in mapping: return mapping[self.error_type] diff --git a/python-api/app/core/platform_config.py b/python-api/app/core/platform_config.py index 3e00e65..29e45da 100644 --- a/python-api/app/core/platform_config.py +++ b/python-api/app/core/platform_config.py @@ -143,9 +143,7 @@ class PlatformConfigLoader: 启动时加载,全环境只读(不支持热重载)。 """ - DEFAULT_CONFIG_PATH = ( - Path(__file__).parent.parent.parent / "config" / "platform-config.yaml" - ) + DEFAULT_CONFIG_PATH = Path(__file__).parent.parent.parent / "config" / "platform-config.yaml" def __init__(self, config_path: str | None = None): self.config_path = Path(config_path) if config_path else self.DEFAULT_CONFIG_PATH @@ -157,9 +155,7 @@ class PlatformConfigLoader: def _load(self) -> None: """加载并校验配置文件""" if not self.config_path.exists(): - raise FileNotFoundError( - f"平台配置文件不存在: {self.config_path}" - ) + raise FileNotFoundError(f"平台配置文件不存在: {self.config_path}") try: with open(self.config_path, encoding="utf-8") as f: @@ -215,18 +211,10 @@ class PlatformConfigLoader: return [m for m in self._models.values() if m.is_enabled] def get_models_by_capability(self, capability: str) -> list[ModelConfig]: - return [ - m - for m in self._models.values() - if m.is_enabled and capability in m.capabilities - ] + return [m for m in self._models.values() if m.is_enabled and capability in m.capabilities] def get_models_by_platform(self, platform_id: str) -> list[ModelConfig]: - return [ - m - for m in self._models.values() - if m.platform_id == platform_id and m.is_enabled - ] + return [m for m in self._models.values() if m.platform_id == platform_id and m.is_enabled] def get_default_model_for_task(self, task_type: str) -> str | None: if self._raw is None: diff --git a/python-api/app/core/redis_client.py b/python-api/app/core/redis_client.py index 819f10d..4c660c8 100644 --- a/python-api/app/core/redis_client.py +++ b/python-api/app/core/redis_client.py @@ -4,6 +4,8 @@ Redis 客户端 全局 Redis 连接,供 Scheduler 和 RateLimiter 使用 """ +from typing import Any + from redis.asyncio import Redis from app.config import get_settings @@ -19,7 +21,7 @@ def get_redis_client() -> Redis: settings = get_settings() # 构建连接参数 - client_kwargs = { + client_kwargs: dict[str, Any] = { "host": settings.REDIS_HOST, "port": settings.REDIS_PORT, "db": settings.REDIS_DB, diff --git a/python-api/app/crud/broll_category.py b/python-api/app/crud/broll_category.py index 3cc42b2..d8e63b4 100644 --- a/python-api/app/crud/broll_category.py +++ b/python-api/app/crud/broll_category.py @@ -70,9 +70,7 @@ class BrollCategoryCRUD(CRUDBase[BrollCategory]): ) return result.scalar_one_or_none() - async def get_by_level( - self, db: AsyncSession, *, level: int - ) -> list[BrollCategory]: + async def get_by_level(self, db: AsyncSession, *, level: int) -> list[BrollCategory]: """根据层级获取所有启用的分类""" result = await db.execute( select(BrollCategory).where( diff --git a/python-api/app/crud/broll_material.py b/python-api/app/crud/broll_material.py index 6a460fb..dafda1c 100644 --- a/python-api/app/crud/broll_material.py +++ b/python-api/app/crud/broll_material.py @@ -49,9 +49,7 @@ class BrollMaterialCRUD(CRUDBase[BrollMaterial]): ) return list(result.scalars().all()) - async def increment_usage_count( - self, db: AsyncSession, *, material_id: int - ) -> None: + async def increment_usage_count(self, db: AsyncSession, *, material_id: int) -> None: """ 原子递增素材使用次数 diff --git a/python-api/app/crud/point_recharge_order.py b/python-api/app/crud/point_recharge_order.py index 943404c..64ffe25 100644 --- a/python-api/app/crud/point_recharge_order.py +++ b/python-api/app/crud/point_recharge_order.py @@ -23,9 +23,7 @@ class PointRechargeOrderCRUD(CRUDBase[PointRechargeOrder]): ) -> PointRechargeOrder | None: """根据商户订单号查询""" result = await db.execute( - select(PointRechargeOrder).where( - PointRechargeOrder.out_trade_no == out_trade_no - ) + select(PointRechargeOrder).where(PointRechargeOrder.out_trade_no == out_trade_no) ) return result.scalar_one_or_none() @@ -34,9 +32,7 @@ class PointRechargeOrderCRUD(CRUDBase[PointRechargeOrder]): ) -> PointRechargeOrder | None: """根据微信支付订单号查询""" result = await db.execute( - select(PointRechargeOrder).where( - PointRechargeOrder.wx_order_no == wx_order_no - ) + select(PointRechargeOrder).where(PointRechargeOrder.wx_order_no == wx_order_no) ) return result.scalar_one_or_none() diff --git a/python-api/app/crud/point_transaction.py b/python-api/app/crud/point_transaction.py index 623b7cc..3e846e9 100644 --- a/python-api/app/crud/point_transaction.py +++ b/python-api/app/crud/point_transaction.py @@ -6,6 +6,7 @@ """ from datetime import datetime, time +from uuid import UUID from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession @@ -24,7 +25,7 @@ class PointTransactionCRUD(CRUDBase[PointTransaction]): self, db: AsyncSession, *, - user_id: str, + user_id: UUID | str, skip: int = 0, limit: int = 50, tx_type: str | None = None, @@ -55,7 +56,7 @@ class PointTransactionCRUD(CRUDBase[PointTransaction]): self, db: AsyncSession, *, - user_id: str, + user_id: UUID | str, tx_type: str | None = None, category: str | None = None, source_type: str | None = None, @@ -105,18 +106,15 @@ class PointTransactionCRUD(CRUDBase[PointTransaction]): self, db: AsyncSession, *, - user_id: str, + user_id: UUID | str, ) -> int: """统计用户今日消费积分总和""" now = datetime.now() start_of_day = datetime.combine(now.date(), time.min) - stmt = ( - select(func.coalesce(func.sum(PointTransaction.amount), 0)) - .where( - PointTransaction.user_id == user_id, - PointTransaction.type == "consume", - PointTransaction.created_at >= start_of_day, - ) + stmt = select(func.coalesce(func.sum(PointTransaction.amount), 0)).where( + PointTransaction.user_id == user_id, + PointTransaction.type == "consume", + PointTransaction.created_at >= start_of_day, ) result = await db.execute(stmt) return result.scalar() or 0 diff --git a/python-api/app/crud/user.py b/python-api/app/crud/user.py index a3bf240..4093ad1 100644 --- a/python-api/app/crud/user.py +++ b/python-api/app/crud/user.py @@ -5,7 +5,11 @@ 用户认证相关的数据访问。 """ +from typing import Any, cast +from uuid import UUID + from sqlalchemy import select +from sqlalchemy.engine import CursorResult from sqlalchemy.ext.asyncio import AsyncSession from app.crud.base import CRUDBase @@ -48,7 +52,7 @@ class UserCRUD(CRUDBase[User]): return user async def update_login_info( - self, db: AsyncSession, *, user_id: str, ip: str | None = None + self, db: AsyncSession, *, user_id: UUID | str, ip: str | None = None ) -> User | None: """ 更新用户最后登录信息 @@ -68,7 +72,7 @@ class UserCRUD(CRUDBase[User]): return user async def update_password( - self, db: AsyncSession, *, user_id: str, password_hash: str + self, db: AsyncSession, *, user_id: UUID | str, password_hash: str ) -> User | None: """更新用户密码""" user = await self.get(db, id=user_id) @@ -80,9 +84,7 @@ class UserCRUD(CRUDBase[User]): await db.refresh(user) return user - async def update_extra( - self, db: AsyncSession, *, user_id: str, extra: dict - ) -> bool: + async def update_extra(self, db: AsyncSession, *, user_id: UUID | str, extra: dict) -> bool: """ 原子更新用户 extra 字段(JSONB) @@ -90,12 +92,8 @@ class UserCRUD(CRUDBase[User]): """ from sqlalchemy import update - stmt = ( - update(User) - .where(User.id == user_id) - .values(extra=extra) - ) - result = await db.execute(stmt) + stmt = update(User).where(User.id == user_id).values(extra=extra) + result = cast(CursorResult[Any], await db.execute(stmt)) await db.commit() return result.rowcount > 0 diff --git a/python-api/app/crud/user_device.py b/python-api/app/crud/user_device.py index 76177c8..01805ea 100644 --- a/python-api/app/crud/user_device.py +++ b/python-api/app/crud/user_device.py @@ -6,6 +6,8 @@ 核心操作是「覆盖」而非「新增」,使用 INSERT ... ON CONFLICT DO UPDATE 保证原子性。 """ +from uuid import UUID + from sqlalchemy import select from sqlalchemy.dialects.postgresql import insert from sqlalchemy.ext.asyncio import AsyncSession @@ -20,18 +22,16 @@ class UserDeviceCRUD(CRUDBase[UserDevice]): def __init__(self) -> None: super().__init__(UserDevice) - async def get_by_user_id(self, db: AsyncSession, *, user_id: str) -> UserDevice | None: + async def get_by_user_id(self, db: AsyncSession, *, user_id: UUID | str) -> UserDevice | None: """根据用户 ID 获取设备记录""" - result = await db.execute( - select(UserDevice).where(UserDevice.user_id == user_id) - ) + result = await db.execute(select(UserDevice).where(UserDevice.user_id == user_id)) return result.scalar_one_or_none() async def create_or_update( self, db: AsyncSession, *, - user_id: str, + user_id: UUID | str, device_id: str, device_name: str | None = None, os_info: str | None = None, @@ -80,12 +80,10 @@ class UserDeviceCRUD(CRUDBase[UserDevice]): await db.commit() # 返回最新的记录 - result = await db.execute( - select(UserDevice).where(UserDevice.user_id == user_id) - ) + result = await db.execute(select(UserDevice).where(UserDevice.user_id == user_id)) return result.scalar_one() - async def delete_by_user_id(self, db: AsyncSession, *, user_id: str) -> bool: + async def delete_by_user_id(self, db: AsyncSession, *, user_id: UUID | str) -> bool: """根据用户 ID 删除设备记录(登出时使用)""" device = await self.get_by_user_id(db, user_id=user_id) if device is None: @@ -100,9 +98,7 @@ class UserDeviceCRUD(CRUDBase[UserDevice]): ) -> UserDevice | None: """根据 Refresh Token 哈希获取设备记录""" result = await db.execute( - select(UserDevice).where( - UserDevice.refresh_token_hash == refresh_token_hash - ) + select(UserDevice).where(UserDevice.refresh_token_hash == refresh_token_hash) ) return result.scalar_one_or_none() diff --git a/python-api/app/main.py b/python-api/app/main.py index 1532248..49851d4 100644 --- a/python-api/app/main.py +++ b/python-api/app/main.py @@ -149,12 +149,8 @@ async def lifespan(app: FastAPI): logger.info("VolcengineMediakitAdapter initialized") if app.state.volcengine_provider: - app.state.volcengine_ark_adapter = VolcengineArkAdapter( - app.state.volcengine_provider - ) - app.state.platform_gateway.register( - "volcengine_ark", app.state.volcengine_ark_adapter - ) + app.state.volcengine_ark_adapter = VolcengineArkAdapter(app.state.volcengine_provider) + app.state.platform_gateway.register("volcengine_ark", app.state.volcengine_ark_adapter) logger.info("VolcengineArkAdapter registered to PlatformGateway") logger.info("PlatformGateway initialized") @@ -177,9 +173,7 @@ async def lifespan(app: FastAPI): logger.info("Vidu Service initialized") if app.state.volcengine_caption_provider: - app.state.volcengine_caption_service = VolcengineCaptionService( - app.state.platform_gateway - ) + app.state.volcengine_caption_service = VolcengineCaptionService(app.state.platform_gateway) logger.info("Volcengine Caption Service initialized") else: app.state.volcengine_caption_service = None @@ -276,12 +270,14 @@ def create_app() -> FastAPI: "code": exc.status_code or http_status, "message": str(exc), "data": None, + "error_code": exc.error_type, } if settings.DEBUG: content["detail"] = { "platform": exc.platform, "error_type": exc.error_type, "retryable": exc.retryable, + "raw_code": exc.raw_code, } return _cors_response(request, http_status, content) @@ -294,6 +290,9 @@ def create_app() -> FastAPI: exc.detail if isinstance(exc.detail, str) else "请求失败" ) detail = exc.detail if isinstance(exc.detail, dict) else None + error_code = getattr(exc, "error_code", None) + if not error_code and isinstance(detail, dict): + error_code = detail.get("error_code") return _cors_response( request, @@ -301,6 +300,7 @@ def create_app() -> FastAPI: { "code": exc.status_code, "message": message, + "error_code": error_code, "detail": detail, }, ) diff --git a/python-api/app/models/bgm_music.py b/python-api/app/models/bgm_music.py index d8cd403..8d72913 100644 --- a/python-api/app/models/bgm_music.py +++ b/python-api/app/models/bgm_music.py @@ -33,18 +33,10 @@ class BgmMusic(BaseModelBigInt): category: Mapped[str] = mapped_column( String(32), nullable=False, index=True, comment="场景分类" ) - file_path: Mapped[str] = mapped_column( - String(512), nullable=False, comment="相对文件路径" - ) - url: Mapped[str] = mapped_column( - String(1024), nullable=False, comment="七牛云 URL" - ) - duration: Mapped[float] = mapped_column( - Float, nullable=True, comment="时长(秒)" - ) + file_path: Mapped[str] = mapped_column(String(512), nullable=False, comment="相对文件路径") + url: Mapped[str] = mapped_column(String(1024), nullable=False, comment="七牛云 URL") + duration: Mapped[float] = mapped_column(Float, nullable=True, comment="时长(秒)") status: Mapped[str] = mapped_column( String(16), default="active", nullable=False, comment="状态: active/inactive" ) - sort_order: Mapped[int] = mapped_column( - Integer, default=0, nullable=False, comment="排序权重" - ) + sort_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="排序权重") diff --git a/python-api/app/models/update.py b/python-api/app/models/update.py index a52610d..5719e74 100644 --- a/python-api/app/models/update.py +++ b/python-api/app/models/update.py @@ -7,7 +7,16 @@ Tauri updater 插件所需的数据结构。 from datetime import UTC, datetime -from sqlalchemy import Boolean, BigInteger, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint +from sqlalchemy import ( + BigInteger, + Boolean, + DateTime, + ForeignKey, + Integer, + String, + Text, + UniqueConstraint, +) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.session import Base @@ -60,5 +69,11 @@ class ReleasePackage(Base): release: Mapped["AppRelease"] = relationship("AppRelease", back_populates="packages") __table_args__ = ( - UniqueConstraint("release_id", "platform", "architecture", "filename", name="uix_app_pkg_platform_arch_filename"), + UniqueConstraint( + "release_id", + "platform", + "architecture", + "filename", + name="uix_app_pkg_platform_arch_filename", + ), ) diff --git a/python-api/app/models/user.py b/python-api/app/models/user.py index c0cb6e4..e6adcc1 100644 --- a/python-api/app/models/user.py +++ b/python-api/app/models/user.py @@ -15,7 +15,7 @@ from sqlalchemy.orm import Mapped, mapped_column from app.models.base import BaseModel -class UserStatus(str, enum.Enum): +class UserStatus(enum.StrEnum): """用户状态""" ACTIVE = "active" # 正常 @@ -117,6 +117,3 @@ class User(BaseModel): def display_name(self) -> str: """对外展示的名称""" return self.nickname or f"用户_{self.mobile[-4:]}" - - - diff --git a/python-api/app/platform_gateway.py b/python-api/app/platform_gateway.py index 89761b9..5815b36 100644 --- a/python-api/app/platform_gateway.py +++ b/python-api/app/platform_gateway.py @@ -24,6 +24,10 @@ from app.ai.adapters.base import ( TaskStatus, ) from app.core.exceptions import PlatformError, PlatformErrorType +from app.utils.content_fingerprint import ( + compute_content_fingerprint, + is_vidu_audit_error, +) logger = logging.getLogger(__name__) @@ -31,6 +35,10 @@ logger = logging.getLogger(__name__) _TASK_MAPPING_PREFIX = "platform_gateway:task_mapping" _TASK_MAPPING_TTL = 7 * 24 * 60 * 60 # 7 天 +# Redis key 前缀:内容审核失败缓存 +_AUDIT_REJECTION_PREFIX = "platform_gateway:audit_rejection" +_AUDIT_REJECTION_TTL = 24 * 60 * 60 # 24 小时 + class PlatformGateway: """第三方平台统一调用网关""" @@ -61,10 +69,13 @@ class PlatformGateway: redis = self._get_redis() # 正向映射:internal → platform key = self._task_mapping_key(internal_task_id) - await redis.hset(key, mapping={ - "platform": platform, - "platform_task_id": platform_task_id, - }) + await redis.hset( + key, + mapping={ + "platform": platform, + "platform_task_id": platform_task_id, + }, + ) await redis.expire(key, _TASK_MAPPING_TTL) # 反向映射:platform → internal(供回调查找) reverse_key = f"{_TASK_MAPPING_PREFIX}:reverse:{platform}:{platform_task_id}" @@ -82,6 +93,33 @@ class PlatformGateway: "platform_task_id": data.get("platform_task_id", ""), } + def _audit_rejection_key(self, fingerprint: str) -> str: + return f"{_AUDIT_REJECTION_PREFIX}:{fingerprint}" + + async def _get_audit_rejection(self, fingerprint: str) -> str | None: + """查询该内容指纹是否近期审核失败。 + + Returns: + 失败错误码(如 "TaskPromptPolicyViolation"),未命中返回 None + """ + if not fingerprint: + return None + try: + redis = self._get_redis() + key = self._audit_rejection_key(fingerprint) + return await redis.get(key) + except Exception as e: + logger.warning(f"[PlatformGateway] 查询审核缓存失败: {e}") + return None + + async def _set_audit_rejection(self, fingerprint: str, error_code: str) -> None: + """缓存审核失败结果。""" + if not fingerprint or not error_code: + return + redis = self._get_redis() + key = self._audit_rejection_key(fingerprint) + await redis.setex(key, _AUDIT_REJECTION_TTL, error_code) + async def get_internal_task_id_by_platform_task_id( self, platform: str, platform_task_id: str ) -> str | None: @@ -156,15 +194,62 @@ class PlatformGateway: 若提供,则直接使用该 ID 建立映射;否则自动生成。 callback 场景必须传入,确保回调能反查到正确的 Registry 记录。 """ + internal_task_id = internal_task_id or uuid.uuid4().hex + + # 1. 同一 internal_task_id 已提交过,直接返回(幂等) + existing = await self._get_task_mapping(internal_task_id) + if existing: + return internal_task_id + + # 2. Vidu 内容指纹防重:相同内容近期审核失败则直接拦截 + fingerprint: str | None = None + if platform == "vidu": + fingerprint = compute_content_fingerprint( + task_type=task_type, + video_url=payload.get("video_url"), + audio_url=payload.get("audio_url"), + ref_photo_url=payload.get("ref_photo_url"), + text=payload.get("text"), + voice_id=payload.get("voice_id"), + ) + rejected_code = await self._get_audit_rejection(fingerprint) + if rejected_code: + raise PlatformError( + "人物分镜台词未通过安全审核,请修改后重试", + platform=platform, + retryable=False, + error_type=PlatformErrorType.CONTENT_VIOLATION, + raw_code=rejected_code, + ) + + # 3. 调用平台 Adapter 提交任务 adapter = self._get_task_adapter(platform, task_type) - result = await adapter.submit(task_type, payload, callback_url) + try: + result = await adapter.submit(task_type, payload, callback_url) + except PlatformError as e: + # Vidu 审核类错误:缓存内容指纹,防止重复调用 + err_code = e.raw_code + if platform == "vidu" and fingerprint and err_code and is_vidu_audit_error(err_code): + await self._set_audit_rejection(fingerprint, err_code) + raise PlatformError( + "人物分镜台词未通过安全审核,请修改后重试", + platform=platform, + retryable=False, + error_type=PlatformErrorType.CONTENT_VIOLATION, + raw_code=err_code, + ) from e + raise if not result.success: + raw_code = result.error_code + if platform == "vidu" and fingerprint and raw_code and is_vidu_audit_error(raw_code): + await self._set_audit_rejection(fingerprint, raw_code) raise PlatformError( result.error_message or "任务提交失败", platform=platform, retryable=result.retryable, error_type=PlatformErrorType.UNKNOWN, + raw_code=raw_code, ) platform_task_id = (result.data or {}).get("task_id", "") @@ -175,7 +260,6 @@ class PlatformGateway: retryable=False, error_type=PlatformErrorType.UNKNOWN, ) - internal_task_id = internal_task_id or uuid.uuid4().hex await self._store_task_mapping(internal_task_id, platform, platform_task_id) logger.info( f"Task submitted: internal={internal_task_id}, " diff --git a/python-api/app/scheduler/engine.py b/python-api/app/scheduler/engine.py index bd6307f..6f43b86 100644 --- a/python-api/app/scheduler/engine.py +++ b/python-api/app/scheduler/engine.py @@ -7,6 +7,7 @@ Async Engine 核心调度器 import asyncio import logging +from datetime import UTC, datetime from typing import Any from app.core.redis_client import get_redis_client @@ -17,6 +18,13 @@ from app.scheduler.slot_manager import SlotManager logger = logging.getLogger(__name__) +# 各任务类型最大执行时间(秒),超过后自动标记为 failed +TASK_TIMEOUT_SECONDS = { + "script": 5 * 60, + "subtitle": 10 * 60, + "video": 30 * 60, +} + class AsyncEngine: """统一异步作业调度引擎""" @@ -46,13 +54,50 @@ class AsyncEngine: logger.debug("Tick: no running tasks") return - # 2. 按 task_type 分组 + # 2. 按 task_type 分组,并处理超时任务 tasks_by_type: dict[str, list[Any]] = {} + timeout_changes: list[StateChange] = [] + now = datetime.now(UTC) + for task_id in running_ids: record = await self.registry.get(task_id) if not record: await self.registry.remove_running(task_id) continue + + max_duration = TASK_TIMEOUT_SECONDS.get(record.task_type) + is_timeout = ( + max_duration + and record.status == "running" + and record.created_at + and (now - datetime.fromisoformat(record.created_at)).total_seconds() > max_duration + ) + + if is_timeout: + logger.warning( + f"Task timeout: {task_id}, type={record.task_type}, " + f"created_at={record.created_at}" + ) + timeout_changes.append( + StateChange(task_id=task_id, field_path="status", value="failed") + ) + timeout_changes.append( + StateChange( + task_id=task_id, + field_path="message", + value="任务执行超时,请稍后重试", + ) + ) + timeout_changes.append( + StateChange( + task_id=task_id, + field_path="error", + value=f"任务执行超过 {max_duration} 秒", + ) + ) + await self.registry.remove_running(task_id) + continue + tasks_by_type.setdefault(record.task_type, []).append(record) # 3. 并行执行各 Handler 的 tick @@ -63,10 +108,14 @@ class AsyncEngine: ] ) - # 4. 收集并应用状态变更 + # 4. 收集并应用状态变更(包含超时任务) + all_changes: list[StateChange] = [] for changes in results: if changes: - await self._apply_changes(changes) + all_changes.extend(changes) + all_changes.extend(timeout_changes) + if all_changes: + await self._apply_changes(all_changes) # 5. 清理已结束的作业 await self._cleanup_finished() diff --git a/python-api/app/scheduler/handlers/script_handler.py b/python-api/app/scheduler/handlers/script_handler.py index b94cb04..028987b 100644 --- a/python-api/app/scheduler/handlers/script_handler.py +++ b/python-api/app/scheduler/handlers/script_handler.py @@ -10,6 +10,7 @@ import logging from typing import Any from app.ai.prompts.loader import _load_system_meta +from app.core.exceptions import InsufficientPointsException from app.core.platform_config import get_platform_config_loader from app.db.session import AsyncSessionLocal from app.scheduler.handlers.base import AsyncHandler @@ -38,6 +39,7 @@ def _get_category_name(category: str, filename: str) -> str: return f"{cat_name} · {label}" return cat_name + SLOT_KEY = "script:slots" @@ -64,9 +66,7 @@ class ScriptHandler(AsyncHandler): def _get_service(self) -> ScriptService: if self.service is None: - raise RuntimeError( - "ScriptHandler 需要通过构造函数传入 ScriptService 实例" - ) + raise RuntimeError("ScriptHandler 需要通过构造函数传入 ScriptService 实例") return self.service async def tick( @@ -83,7 +83,9 @@ class ScriptHandler(AsyncHandler): changes.extend(await self._process_task(task, registry, slots)) except Exception as e: logger.exception(f"[Script {task.task_id}] failed") - changes.append(StateChange(task_id=task.task_id, field_path="status", value="failed")) + changes.append( + StateChange(task_id=task.task_id, field_path="status", value="failed") + ) changes.append( StateChange(task_id=task.task_id, field_path="error", value=str(e)[:500]) ) @@ -129,30 +131,66 @@ class ScriptHandler(AsyncHandler): "shot_count": len(shots), } - changes.append(StateChange(task_id=task.task_id, field_path="status", value="completed")) + # 生成成功后再扣费 + user_id = params.get("user_id") + required_points = params.get("required_points", 0) + if user_id and required_points > 0: + try: + async with AsyncSessionLocal() as db: + await ps.consume( + db, + user_id=user_id, + points=required_points, + source_type="script", + source_id=task.task_id, + description="【脚本生成】", + ) + await db.commit() + except InsufficientPointsException: + changes.append( + StateChange(task_id=task.task_id, field_path="status", value="failed") + ) + changes.append( + StateChange( + task_id=task.task_id, + field_path="message", + value="积分不足", + ) + ) + changes.append( + StateChange( + task_id=task.task_id, + field_path="error_code", + value="insufficient_points", + ) + ) + return changes + except Exception as e: + logger.error(f"[ScriptTask {task.task_id}] 扣费失败: {e}") + changes.append( + StateChange(task_id=task.task_id, field_path="status", value="failed") + ) + changes.append( + StateChange( + task_id=task.task_id, + field_path="message", + value="扣费失败", + ) + ) + return changes + + changes.append( + StateChange(task_id=task.task_id, field_path="status", value="completed") + ) changes.append(StateChange(task_id=task.task_id, field_path="progress", value=100)) changes.append( StateChange(task_id=task.task_id, field_path="message", value="脚本生成完成") ) changes.append(StateChange(task_id=task.task_id, field_path="completed", value=1)) changes.append(StateChange(task_id=task.task_id, field_path="total", value=1)) - changes.append(StateChange(task_id=task.task_id, field_path="result", value=result_data)) - - # 后置扣费(独立 session,失败不影响任务结果) - try: - async with AsyncSessionLocal() as db: - points = ps._calculate_cost("script") - await ps.consume( - db, - user_id=task.user_id, - points=points, - source_type="script", - source_id=task.task_id, - description="【脚本生成】", - ) - await db.commit() - except Exception as e: - logger.error(f"[Script {task.task_id}] 扣费失败: {e}") + changes.append( + StateChange(task_id=task.task_id, field_path="result", value=result_data) + ) except Exception as exc: logger.exception(f"[ScriptTask {task.task_id}] Failed") @@ -160,6 +198,8 @@ class ScriptHandler(AsyncHandler): changes.append( StateChange(task_id=task.task_id, field_path="message", value=str(exc)[:200]) ) - changes.append(StateChange(task_id=task.task_id, field_path="error", value=str(exc)[:500])) + changes.append( + StateChange(task_id=task.task_id, field_path="error", value=str(exc)[:500]) + ) return changes diff --git a/python-api/app/scheduler/handlers/subtitle_handler.py b/python-api/app/scheduler/handlers/subtitle_handler.py index 510026b..65a8bd1 100644 --- a/python-api/app/scheduler/handlers/subtitle_handler.py +++ b/python-api/app/scheduler/handlers/subtitle_handler.py @@ -45,9 +45,7 @@ class SubtitleHandler(AsyncHandler): def _get_service(self) -> VolcengineCaptionService: if self.service is None: - raise RuntimeError( - "SubtitleHandler 需要通过构造函数传入 VolcengineCaptionService 实例" - ) + raise RuntimeError("SubtitleHandler 需要通过构造函数传入 VolcengineCaptionService 实例") return self.service async def tick( @@ -93,7 +91,9 @@ class SubtitleHandler(AsyncHandler): "utterances": utterances, } changes.append( - StateChange(task_id=task.task_id, field_path="status", value="completed") + StateChange( + task_id=task.task_id, field_path="status", value="completed" + ) ) changes.append( StateChange(task_id=task.task_id, field_path="progress", value=100) @@ -106,9 +106,13 @@ class SubtitleHandler(AsyncHandler): changes.append( StateChange(task_id=task.task_id, field_path="completed", value=1) ) - changes.append(StateChange(task_id=task.task_id, field_path="total", value=1)) changes.append( - StateChange(task_id=task.task_id, field_path="result", value=result_payload) + StateChange(task_id=task.task_id, field_path="total", value=1) + ) + changes.append( + StateChange( + task_id=task.task_id, field_path="result", value=result_payload + ) ) elif status.state == "failed": changes.append( @@ -173,9 +177,13 @@ class SubtitleHandler(AsyncHandler): if not volc_task_id: raise ValueError("未返回任务ID") params["volc_task_id"] = volc_task_id - changes.append(StateChange(task_id=task.task_id, field_path="params", value=params)) changes.append( - StateChange(task_id=task.task_id, field_path="message", value="字幕任务已提交") + StateChange(task_id=task.task_id, field_path="params", value=params) + ) + changes.append( + StateChange( + task_id=task.task_id, field_path="message", value="字幕任务已提交" + ) ) except RuntimeError: logger.error(f"[Subtitle {task.task_id}] service not initialized") diff --git a/python-api/app/scheduler/handlers/video_handler.py b/python-api/app/scheduler/handlers/video_handler.py index 49b023e..be2084a 100644 --- a/python-api/app/scheduler/handlers/video_handler.py +++ b/python-api/app/scheduler/handlers/video_handler.py @@ -9,17 +9,27 @@ Video 任务处理器 import logging from typing import Any +from app.core.exceptions import PlatformError, PlatformErrorType from app.core.platform_config import get_platform_config_loader +from app.core.redis_client import get_redis_client from app.scheduler.handlers.base import AsyncHandler from app.scheduler.models import StateChange from app.scheduler.registry import TaskRegistry from app.scheduler.slot_manager import SlotManager from app.services.vidu_service import ViduService +from app.utils.content_fingerprint import ( + compute_content_fingerprint, + extract_vidu_error_code, + is_vidu_audit_error, +) logger = logging.getLogger(__name__) SLOT_KEY = "vidu:video_slots" +_AUDIT_REJECTION_PREFIX = "platform_gateway:audit_rejection" +_AUDIT_REJECTION_TTL = 24 * 60 * 60 # 24 小时 + def _get_video_max_slots() -> int: """从 platform-config.yaml 读取 rate_limit 配置作为 max_slots""" @@ -45,11 +55,39 @@ class VideoHandler(AsyncHandler): def _get_service(self) -> ViduService: if self.service is None: - raise RuntimeError( - "VideoHandler 需要通过构造函数传入 ViduService 实例" - ) + raise RuntimeError("VideoHandler 需要通过构造函数传入 ViduService 实例") return self.service + async def _cache_audit_rejection_if_needed( + self, params: dict[str, Any], error_message: str | None + ) -> None: + """如果失败原因是 Vidu 审核类错误,缓存内容指纹防止重复提交。""" + err_code = extract_vidu_error_code(error_message) + if not err_code or not is_vidu_audit_error(err_code): + return + + fingerprint = compute_content_fingerprint( + task_type="lip_sync", + video_url=params.get("video_url"), + audio_url=params.get("audio_url"), + ref_photo_url=params.get("ref_photo_url"), + text=params.get("text"), + voice_id=params.get("voice_id"), + ) + if not fingerprint: + return + + try: + redis = get_redis_client() + key = f"{_AUDIT_REJECTION_PREFIX}:{fingerprint}" + await redis.setex(key, _AUDIT_REJECTION_TTL, err_code) + logger.info( + f"[Video] 审核失败内容已缓存: fingerprint={fingerprint[:16]}..., " + f"err_code={err_code}" + ) + except Exception as e: + logger.warning(f"[Video] 缓存审核失败结果出错: {e}") + async def tick( self, tasks: list[Any], registry: TaskRegistry, slots: SlotManager ) -> list[StateChange]: @@ -87,11 +125,7 @@ class VideoHandler(AsyncHandler): value=1, ) ) - changes.append( - StateChange( - task_id=task.task_id, field_path="total", value=1 - ) - ) + changes.append(StateChange(task_id=task.task_id, field_path="total", value=1)) elif task.status == "failed": # callback 已标记失败,移除 running await registry.remove_running(task.task_id) @@ -150,6 +184,15 @@ class VideoHandler(AsyncHandler): f"video_url={video_url[:60]}..." ) elif vidu_state == "failed": + error_message = vidu_status.get("message") or "视频生成失败" + err_code = extract_vidu_error_code(error_message) + is_audit = err_code and is_vidu_audit_error(err_code) + message = ( + "人物分镜台词未通过安全审核,请修改后重试" + if is_audit + else "视频生成失败" + ) + changes.append( StateChange( task_id=task.task_id, @@ -161,20 +204,29 @@ class VideoHandler(AsyncHandler): StateChange( task_id=task.task_id, field_path="message", - value="视频生成失败", + value=message, ) ) changes.append( StateChange( task_id=task.task_id, field_path="error", - value=vidu_status.get("message") or "视频生成失败", + value=error_message, ) ) + if is_audit: + changes.append( + StateChange( + task_id=task.task_id, + field_path="error_code", + value="content_violation", + ) + ) + await self._cache_audit_rejection_if_needed(params, error_message) await registry.remove_running(task.task_id) logger.warning( f"[Video {task.task_id}] 主动查询 Vidu 任务失败: " - f"{vidu_status.get('message')}" + f"{error_message}" ) else: # 仍在处理中,继续等待 @@ -182,15 +234,11 @@ class VideoHandler(AsyncHandler): f"[Video {task.task_id}] 主动查询 Vidu 状态: {vidu_state},继续等待" ) except Exception as e: - logger.warning( - f"[Video {task.task_id}] 主动查询 Vidu 失败: {e}" - ) + logger.warning(f"[Video {task.task_id}] 主动查询 Vidu 失败: {e}") continue # ← 已提交,不再重复提交 # 提交阶段:占用 slot,提交成功后自动释放 - async with slots.acquire_ctx( - SLOT_KEY, task.task_id, self.max_slots - ) as acquired: + async with slots.acquire_ctx(SLOT_KEY, task.task_id, self.max_slots) as acquired: if not acquired: continue @@ -227,9 +275,7 @@ class VideoHandler(AsyncHandler): raise ValueError("未返回任务ID") params["vidu_task_id"] = vidu_task_id changes.append( - StateChange( - task_id=task.task_id, field_path="params", value=params - ) + StateChange(task_id=task.task_id, field_path="params", value=params) ) changes.append( StateChange( @@ -241,9 +287,7 @@ class VideoHandler(AsyncHandler): except RuntimeError: logger.error(f"[Video {task.task_id}] service not initialized") changes.append( - StateChange( - task_id=task.task_id, field_path="status", value="failed" - ) + StateChange(task_id=task.task_id, field_path="status", value="failed") ) changes.append( StateChange( @@ -259,12 +303,50 @@ class VideoHandler(AsyncHandler): value="视频处理服务未就绪", ) ) + except PlatformError as e: + error_message = str(e) + is_audit = e.error_type == PlatformErrorType.CONTENT_VIOLATION + if is_audit: + message = "人物分镜台词未通过安全审核,请修改后重试" + elif e.error_type == PlatformErrorType.AUTH_FAILED: + message = "视频服务认证失败,请联系客服" + elif e.error_type == PlatformErrorType.RATE_LIMIT: + message = "视频生成服务繁忙,请稍后重试" + else: + message = "视频生成任务提交失败,请稍后重试" + + logger.error(f"[Video {task.task_id}] submit platform error: {e}") + changes.append( + StateChange(task_id=task.task_id, field_path="status", value="failed") + ) + changes.append( + StateChange( + task_id=task.task_id, + field_path="message", + value=message, + ) + ) + changes.append( + StateChange( + task_id=task.task_id, + field_path="error", + value=error_message, + ) + ) + if is_audit: + changes.append( + StateChange( + task_id=task.task_id, + field_path="error_code", + value="content_violation", + ) + ) + # 审核类错误在 PlatformGateway 已写缓存,此处幂等补充 + await self._cache_audit_rejection_if_needed(params, error_message) except Exception as e: logger.error(f"[Video {task.task_id}] submit error: {e}") changes.append( - StateChange( - task_id=task.task_id, field_path="status", value="failed" - ) + StateChange(task_id=task.task_id, field_path="status", value="failed") ) changes.append( StateChange( diff --git a/python-api/app/scheduler/models.py b/python-api/app/scheduler/models.py index e9a9161..b6f24c1 100644 --- a/python-api/app/scheduler/models.py +++ b/python-api/app/scheduler/models.py @@ -24,6 +24,7 @@ class TaskRecord: total: int = 0 result: dict[str, Any] = field(default_factory=dict) error: str | None = None + error_code: str | None = None params: dict[str, Any] | Any = field(default_factory=dict) created_at: str = "" diff --git a/python-api/app/scheduler/registry.py b/python-api/app/scheduler/registry.py index a3be293..ecbf647 100644 --- a/python-api/app/scheduler/registry.py +++ b/python-api/app/scheduler/registry.py @@ -7,8 +7,9 @@ import json import logging +from collections.abc import Awaitable from datetime import UTC -from typing import Any +from typing import Any, cast from redis.asyncio import Redis @@ -54,8 +55,8 @@ class TaskRegistry: if params: data["params"] = json.dumps(params, ensure_ascii=False) - await self.redis.hset(_task_key(task_id), mapping=data) - await self.redis.expire(_task_key(task_id), ttl) + await cast(Awaitable[int], self.redis.hset(_task_key(task_id), mapping=data)) + await cast(Awaitable[int], self.redis.expire(_task_key(task_id), ttl)) logger.debug(f"Registry created: {task_id}, type={task_type}") async def update(self, task_id: str, **fields: Any) -> None: @@ -68,12 +69,12 @@ class TaskRegistry: mapping[key] = "" else: mapping[key] = str(value) - await self.redis.hset(_task_key(task_id), mapping=mapping) + await cast(Awaitable[int], self.redis.hset(_task_key(task_id), mapping=mapping)) logger.debug(f"Registry updated: {task_id}, fields={list(fields.keys())}") async def get(self, task_id: str) -> TaskRecord | None: """读取完整作业记录""" - data = await self.redis.hgetall(_task_key(task_id)) + data = await cast(Awaitable[dict[Any, Any]], self.redis.hgetall(_task_key(task_id))) if not data: return None @@ -88,6 +89,8 @@ class TaskRegistry: return int(raw) except ValueError: return 0 + if key in ("error_code", "error") and raw == "": + return None return raw parsed = {k: _parse(k, v) for k, v in data.items()} @@ -107,21 +110,22 @@ class TaskRegistry: total=parsed.get("total", 0), result=parsed.get("result", {}), error=parsed.get("error"), + error_code=parsed.get("error_code"), params=params, created_at=parsed.get("created_at", ""), ) async def add_running(self, task_id: str) -> None: """将作业标记为 running(加入全局 running 集合)""" - await self.redis.sadd(KEY_RUNNING_SET, task_id) + await cast(Awaitable[int], self.redis.sadd(KEY_RUNNING_SET, task_id)) async def remove_running(self, task_id: str) -> None: """将作业从全局 running 集合移除""" - await self.redis.srem(KEY_RUNNING_SET, task_id) + await cast(Awaitable[int], self.redis.srem(KEY_RUNNING_SET, task_id)) async def get_running_task_ids(self) -> list[str]: """获取所有 running 的作业 ID 列表""" - members = await self.redis.smembers(KEY_RUNNING_SET) + members = await cast(Awaitable[set[Any]], self.redis.smembers(KEY_RUNNING_SET)) return list(members) async def list_running_by_user(self, user_id: str) -> list[TaskRecord]: @@ -139,5 +143,5 @@ class TaskRegistry: async def delete(self, task_id: str) -> None: """删除作业记录""" - await self.redis.delete(_task_key(task_id)) - await self.redis.srem(KEY_RUNNING_SET, task_id) + await cast(Awaitable[int], self.redis.delete(_task_key(task_id))) + await cast(Awaitable[int], self.redis.srem(KEY_RUNNING_SET, task_id)) diff --git a/python-api/app/scheduler/slot_manager.py b/python-api/app/scheduler/slot_manager.py index acf2e56..5ceb165 100644 --- a/python-api/app/scheduler/slot_manager.py +++ b/python-api/app/scheduler/slot_manager.py @@ -6,7 +6,9 @@ """ import logging +from collections.abc import Awaitable from contextlib import asynccontextmanager +from typing import cast from redis.asyncio import Redis @@ -37,7 +39,9 @@ class SlotManager: async def acquire(self, slot_key: str, slot_id: str, max_slots: int) -> bool: """申请一个槽位。返回 True 表示成功,False 表示槽位已满。""" try: - result = await self.redis.eval(_ACQUIRE_LUA, 1, slot_key, slot_id, str(max_slots)) + result = await cast( + Awaitable[str], self.redis.eval(_ACQUIRE_LUA, 1, slot_key, slot_id, str(max_slots)) + ) acquired = result == 1 if acquired: logger.debug(f"Slot acquired: {slot_key}/{slot_id} (max={max_slots})") @@ -51,7 +55,7 @@ class SlotManager: async def release(self, slot_key: str, slot_id: str) -> None: """释放一个槽位。""" try: - await self.redis.srem(slot_key, slot_id) + await cast(Awaitable[int], self.redis.srem(slot_key, slot_id)) logger.debug(f"Slot released: {slot_key}/{slot_id}") except Exception as e: logger.warning(f"Slot release error: {slot_key}/{slot_id}: {e}") @@ -78,6 +82,6 @@ class SlotManager: async def count(self, slot_key: str) -> int: """获取当前已占用的槽位数量。""" try: - return await self.redis.scard(slot_key) + return await cast(Awaitable[int], self.redis.scard(slot_key)) except Exception: return 0 diff --git a/python-api/app/schemas/bgm_music.py b/python-api/app/schemas/bgm_music.py index 2eb12a4..d3ef372 100644 --- a/python-api/app/schemas/bgm_music.py +++ b/python-api/app/schemas/bgm_music.py @@ -3,7 +3,7 @@ ============== """ -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field class BgmMusicItem(BaseModel): @@ -18,8 +18,7 @@ class BgmMusicItem(BaseModel): duration: float | None = Field(default=None, description="时长(秒)") sort_order: int = Field(default=0, description="排序权重") - class Config: - from_attributes = True + model_config = ConfigDict(from_attributes=True) class BgmMusicListResponse(BaseModel): diff --git a/python-api/app/schemas/common.py b/python-api/app/schemas/common.py index 89c581b..20d1c70 100644 --- a/python-api/app/schemas/common.py +++ b/python-api/app/schemas/common.py @@ -6,14 +6,12 @@ { code: number; data: T; message: string } """ -from typing import Any, Generic, TypeVar +from typing import Any -from pydantic import BaseModel, Field - -T = TypeVar("T") +from pydantic import BaseModel, ConfigDict, Field -class ApiResponse(BaseModel, Generic[T]): +class ApiResponse[T](BaseModel): """ 统一 API 响应格式 @@ -27,17 +25,18 @@ class ApiResponse(BaseModel, Generic[T]): data: T | None = Field(default=None, description="响应数据") message: str = Field(default="success", description="提示信息") - class Config: - json_schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "example": { "code": 200, "data": {}, "message": "success", } } + ) -class PaginatedData(BaseModel, Generic[T]): +class PaginatedData[T](BaseModel): """分页数据包装""" items: list[T] = Field(description="数据列表") @@ -61,18 +60,23 @@ class PaginationParams(BaseModel): class ApiErrorResponse(BaseModel): """错误响应格式""" - code: int = Field(description="错误码") + code: int = Field(description="HTTP 状态码") message: str = Field(description="错误信息") + error_code: str | None = Field(default=None, description="应用级错误码") detail: dict[str, Any] | None = Field(default=None, description="详细错误信息") -def success_response(data: T | None = None, message: str = "success") -> ApiResponse[T]: +def success_response[T](data: T | None = None, message: str = "success") -> ApiResponse[T]: """构造成功响应""" return ApiResponse(code=200, data=data, message=message) def error_response( - code: int, message: str, detail: dict[str, Any] | None = None + code: int, + message: str, + detail: dict[str, Any] | None = None, + *, + error_code: str | None = None, ) -> ApiErrorResponse: """构造错误响应""" - return ApiErrorResponse(code=code, message=message, detail=detail) + return ApiErrorResponse(code=code, message=message, error_code=error_code, detail=detail) diff --git a/python-api/app/schemas/enums.py b/python-api/app/schemas/enums.py index 603bb33..420804d 100644 --- a/python-api/app/schemas/enums.py +++ b/python-api/app/schemas/enums.py @@ -25,6 +25,3 @@ class SegmentStatus(StrEnum): PROCESSING = "processing" COMPLETED = "completed" FAILED = "failed" - - - diff --git a/python-api/app/schemas/materials.py b/python-api/app/schemas/materials.py index 900477e..7550e7e 100644 --- a/python-api/app/schemas/materials.py +++ b/python-api/app/schemas/materials.py @@ -18,9 +18,7 @@ class MatchMaterialRequest(BaseModel): scene: str = Field(description="分镜场景描述") duration: float = Field(description="所需时长(秒)", gt=0) - project_id: str | None = Field( - default=None, description="项目ID,用于跨分镜去重" - ) + project_id: str | None = Field(default=None, description="项目ID,用于跨分镜去重") @field_validator("scene") @classmethod @@ -56,9 +54,7 @@ class BatchMatchSceneItem(BaseModel): class BatchMatchMaterialRequest(BaseModel): """批量匹配素材请求""" - project_id: str | None = Field( - default=None, description="项目ID,用于跨分镜去重" - ) + project_id: str | None = Field(default=None, description="项目ID,用于跨分镜去重") scenes: list[BatchMatchSceneItem] = Field( description="分镜场景列表", min_length=1, @@ -76,6 +72,4 @@ class BatchMatchMaterialResponse(BaseModel): """批量匹配素材响应""" project_id: str | None = Field(description="项目ID") - results: list[MaterialInfo | None] = Field( - description="匹配结果列表,与 scenes 一一对应" - ) + results: list[MaterialInfo | None] = Field(description="匹配结果列表,与 scenes 一一对应") diff --git a/python-api/app/schemas/point.py b/python-api/app/schemas/point.py index b4a4765..cf98bf7 100644 --- a/python-api/app/schemas/point.py +++ b/python-api/app/schemas/point.py @@ -9,6 +9,7 @@ from pydantic import BaseModel, ConfigDict, Field # ── 余额查询 ────────────────────────────────────────── + class PointBalanceResponse(BaseModel): """积分余额响应""" @@ -20,6 +21,7 @@ class PointBalanceResponse(BaseModel): # ── 流水记录 ────────────────────────────────────────── + class PointTransactionItem(BaseModel): """单条流水记录""" @@ -33,7 +35,10 @@ class PointTransactionItem(BaseModel): source_type: str | None = Field(None, description="消费来源类型") source_id: str | None = Field(None, description="消费来源业务 ID") duration: float | None = Field(None, description="时长(秒),按秒计费业务记录") - category: str | None = Field(None, description="业务分类:脚本生成 / 配音合成 / 视频生成 / 压制成片 / 字幕烧录 / 封面设计 / 充值") + category: str | None = Field( + None, + description="业务分类:脚本生成 / 配音合成 / 视频生成 / 压制成片 / 字幕烧录 / 封面设计 / 充值", + ) description: str | None = None created_at: datetime @@ -49,6 +54,7 @@ class PointTransactionListResponse(BaseModel): # ── 充值 ────────────────────────────────────────────── + class RechargeRequest(BaseModel): """充值请求""" @@ -70,6 +76,7 @@ class RechargeResponse(BaseModel): # ── 积分预估 ────────────────────────────────────────── + class CostEstimateResponse(BaseModel): """积分预估响应""" @@ -80,6 +87,7 @@ class CostEstimateResponse(BaseModel): # ── 充值订单 ────────────────────────────────────────── + class RechargeOrderItem(BaseModel): """充值订单记录""" @@ -104,11 +112,16 @@ class RechargeOrderListResponse(BaseModel): # ── 消费扣费 ────────────────────────────────────────── + class ConsumeRequest(BaseModel): """消费扣费请求(供前端/Rust 层调用)""" points: int = Field(gt=0, description="消耗积分数量") - source_type: str = Field(description="消费来源类型,如 compose / subtitle_burn / cover_design / video") + source_type: str = Field( + description="消费来源类型,如 compose / subtitle_burn / cover_design / video" + ) source_id: str = Field(description="消费来源业务 ID") description: str | None = Field(default=None, description="消费描述") - allow_negative: bool = Field(default=False, description="是否允许扣费后余额为负(不确定消耗场景用)") + allow_negative: bool = Field( + default=False, description="是否允许扣费后余额为负(不确定消耗场景用)" + ) diff --git a/python-api/app/schemas/script.py b/python-api/app/schemas/script.py index 7f2e9a5..4ea2807 100644 --- a/python-api/app/schemas/script.py +++ b/python-api/app/schemas/script.py @@ -3,7 +3,6 @@ =============== """ - from pydantic import BaseModel, ConfigDict, Field from app.schemas.segment import Segment @@ -93,7 +92,9 @@ class GenerateTitleRequest(BaseModel): script_content: str = Field(..., description="脚本内容(utterances 文本拼接)", min_length=1) title_type: str = Field(..., description="标题类型:main(大标题) / sub(小标题)") max_length: int = Field(default=8, ge=1, le=100, description="最大字数限制") - usage: str = Field(default="video", description="使用场景:video(视频画面标题) / cover(封面标题)") + usage: str = Field( + default="video", description="使用场景:video(视频画面标题) / cover(封面标题)" + ) class GenerateTitleResponse(BaseModel): diff --git a/python-api/app/schemas/segment.py b/python-api/app/schemas/segment.py index 927c31d..f1f1442 100644 --- a/python-api/app/schemas/segment.py +++ b/python-api/app/schemas/segment.py @@ -32,9 +32,7 @@ class Segment(BaseModel): duration: int | None = Field(default=None, description="时长(秒)") voice_id: str | None = Field(default=None, description="音色ID(空镜时使用)") status: SegmentStatus = Field(default=SegmentStatus.PENDING) - provider_task_id: str | None = Field( - default=None, description="供应商任务ID" - ) + provider_task_id: str | None = Field(default=None, description="供应商任务ID") video_url: str | None = Field(default=None, description="生成后的视频URL") local_path: str | None = Field(default=None, description="本地视频路径") qiniu_url: str | None = Field(default=None, description="七牛云URL") diff --git a/python-api/app/schemas/update.py b/python-api/app/schemas/update.py index e33b97c..9681906 100644 --- a/python-api/app/schemas/update.py +++ b/python-api/app/schemas/update.py @@ -6,7 +6,6 @@ Tauri updater 插件所需的请求/响应模型。 """ from datetime import datetime -from typing import Optional from pydantic import BaseModel, Field @@ -58,6 +57,7 @@ class ReleaseListItem(BaseModel): # Tauri updater 插件所需的 JSON 格式 # ------------------------------------------------------------------ + class TauriPlatformInfo(BaseModel): """Tauri updater 单平台信息""" @@ -73,7 +73,7 @@ class TauriUpdateResponse(BaseModel): version: str = Field(..., description="新版本号") notes: str = Field(default="", description="更新说明") - pub_date: Optional[str] = Field(default=None, description="发布时间(RFC 3339)") + pub_date: str | None = Field(default=None, description="发布时间(RFC 3339)") mandatory: bool = Field(default=False, description="是否强制更新(自定义扩展字段)") platforms: dict[str, TauriPlatformInfo] = Field( ..., description="平台安装包映射,key 格式:OS-ARCH" diff --git a/python-api/app/schemas/user.py b/python-api/app/schemas/user.py index 54c5fba..e5b2c7a 100644 --- a/python-api/app/schemas/user.py +++ b/python-api/app/schemas/user.py @@ -6,7 +6,7 @@ from datetime import datetime from uuid import UUID -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field class UserInfo(BaseModel): @@ -30,8 +30,7 @@ class UserProfileResponse(BaseModel): last_login_at: datetime | None = Field(None, description="最后登录时间") created_at: datetime = Field(..., description="注册时间") - class Config: - from_attributes = True + model_config = ConfigDict(from_attributes=True) class UpdateNicknameRequest(BaseModel): diff --git a/python-api/app/services/ai_response_utils.py b/python-api/app/services/ai_response_utils.py index 45f4a2d..f83ed92 100644 --- a/python-api/app/services/ai_response_utils.py +++ b/python-api/app/services/ai_response_utils.py @@ -220,7 +220,10 @@ def validate_and_normalize_shots(raw_data: Any) -> list[dict[str, Any]]: duration = item.get("duration") duration_str = parse_duration(duration) # 返回如 "5s" try: - normalized["duration"] = int(re.search(r"\d+", duration_str).group()) + match = re.search(r"\d+", duration_str) + if match is None: + raise ValueError("时长字符串中未找到数字") + normalized["duration"] = int(match.group()) except (AttributeError, ValueError): normalized["duration"] = 5 diff --git a/python-api/app/services/auth_service.py b/python-api/app/services/auth_service.py index 5607515..f17fd4a 100644 --- a/python-api/app/services/auth_service.py +++ b/python-api/app/services/auth_service.py @@ -14,6 +14,7 @@ import hashlib import logging import random from typing import Any +from uuid import UUID import httpx from sqlalchemy.ext.asyncio import AsyncSession @@ -32,9 +33,9 @@ from app.models.user_device import UserDevice logger = logging.getLogger(__name__) # ── 短信业务常量(数值类配置不走 .env,内嵌代码)───── -SMS_CODE_LENGTH = 6 # 验证码位数 -SMS_CODE_EXPIRE_MINUTES = 5 # 验证码有效期(分钟) -SMS_DAILY_LIMIT = 10 # 单手机号每日发送上限 +SMS_CODE_LENGTH = 6 # 验证码位数 +SMS_CODE_EXPIRE_MINUTES = 5 # 验证码有效期(分钟) +SMS_DAILY_LIMIT = 10 # 单手机号每日发送上限 # ========== SSE 连接池 ========== # key: user_id, value: asyncio.Queue(用于向该用户的 SSE 连接发送消息) @@ -73,6 +74,7 @@ async def _kick_old_device(user_id: str) -> None: # ========== 验证码校验 ========== + async def verify_sms_code(mobile: str, code: str) -> bool: """ 校验短信验证码。 @@ -145,9 +147,7 @@ async def send_sms_code(mobile: str) -> str: ) else: # 配置不完整,记录警告但不打印验证码 - logger.warning( - f"[SMS] B2M 短信配置不完整,验证码未发送: 手机号={mobile}" - ) + logger.warning(f"[SMS] B2M 短信配置不完整,验证码未发送: 手机号={mobile}") except SMSError as e: logger.error(f"[SMS] 短信发送失败: {e}") # 短信发送失败不影响验证码生成 @@ -159,6 +159,7 @@ async def send_sms_code(mobile: str) -> str: # ========== Token 工具 ========== + def _hash_refresh_token(token: str) -> str: """Refresh Token SHA256 哈希(用于数据库存储)""" return hashlib.sha256(token.encode()).hexdigest() @@ -166,6 +167,7 @@ def _hash_refresh_token(token: str) -> str: # ========== 登录服务 ========== + async def login_with_sms( db: AsyncSession, *, @@ -260,9 +262,7 @@ async def refresh_access_token( refresh_token_hash = _hash_refresh_token(refresh_token) # 2. 查设备记录 - device = await device_crud.get_by_refresh_token_hash( - db, refresh_token_hash=refresh_token_hash - ) + device = await device_crud.get_by_refresh_token_hash(db, refresh_token_hash=refresh_token_hash) if device is None: raise ValueError("设备已失效,请重新登录") @@ -397,7 +397,7 @@ async def reset_password_with_sms( return True -async def logout(db: AsyncSession, *, user_id: str) -> bool: +async def logout(db: AsyncSession, *, user_id: UUID | str) -> bool: """ 用户登出。 @@ -406,14 +406,14 @@ async def logout(db: AsyncSession, *, user_id: str) -> bool: 2. 注销 SSE 连接 """ await device_crud.delete_by_user_id(db, user_id=user_id) - unregister_sse_connection(user_id) + unregister_sse_connection(str(user_id)) return True async def get_current_user_device( db: AsyncSession, *, - user_id: str, + user_id: UUID | str, ) -> UserDevice | None: """获取当前用户的设备记录""" return await device_crud.get_by_user_id(db, user_id=user_id) diff --git a/python-api/app/services/material_service.py b/python-api/app/services/material_service.py index d74824c..9c1fa12 100644 --- a/python-api/app/services/material_service.py +++ b/python-api/app/services/material_service.py @@ -9,6 +9,8 @@ import logging import math import random import re +from collections.abc import Awaitable +from typing import Any, cast from sqlalchemy.ext.asyncio import AsyncSession @@ -16,6 +18,7 @@ from app.core.exceptions import ValidationException from app.core.redis_client import get_redis_client from app.crud import broll_category, broll_material from app.models.broll_category import BrollCategory +from app.models.broll_material import BrollMaterial logger = logging.getLogger(__name__) @@ -28,13 +31,13 @@ def _normalize_scene(scene: str) -> str: # 去除所有 Unicode 空白字符(空格、全角空格、换行、tab 等) cleaned = re.sub(r"\s+", "", scene) # 去除常见中文标点符号(逗号、句号、感叹号、问号、顿号、分号、冒号、引号、括号等) - cleaned = re.sub(r"[,。!?、;:""''()【】《》]+", "", cleaned) + cleaned = re.sub(r"[,。!?、;:" "''()【】《》]+", "", cleaned) # 去除零宽字符(零宽空格、零宽非连接符、零宽连接符、零宽非断空格等) cleaned = re.sub(r"[\u200b-\u200f\ufeff]+", "", cleaned) return cleaned -def _weighted_choice(materials: list) -> object: # noqa: ANN001 +def _weighted_choice(materials: list[BrollMaterial]) -> BrollMaterial: """ 加权随机选择素材 @@ -50,9 +53,9 @@ def _weighted_choice(materials: list) -> object: # noqa: ANN001 total_weight = sum(weights) if total_weight == 0: - return random.choice(materials) + return random.choice(materials) # nosec B311 素材抽样,非加密场景 - r = random.uniform(0, total_weight) + r = random.uniform(0, total_weight) # nosec B311 素材抽样,非加密场景 cumulative = 0.0 for m, w in zip(materials, weights, strict=True): cumulative += w @@ -74,10 +77,9 @@ async def _try_fallback_to_parent( - 若 scene 含 '-',取后半部分作为 parent_name(如 '电路施工-电路施工' -> '电路施工') - 若不含 '-',直接以整个 scene 作为 parent_name - 匹配策略(逐级降级): + 匹配策略: 1. 精确匹配 level=2 分类 name - 2. 模糊匹配(LIKE %parent_name%),兼容 "电路施工" → "电路施工镜" - 3. 去掉常见后缀(镜、阶段等)再精确匹配 + 2. 模糊匹配(LIKE %parent_name%) 返回: 随机选中的一个 level=3 子分类,或 None @@ -88,37 +90,20 @@ async def _try_fallback_to_parent( parent_name = normalized_scene # 1. 精确匹配 - parent = await broll_category.get_by_name_and_level( - db, name=parent_name, level=2 - ) + parent = await broll_category.get_by_name_and_level(db, name=parent_name, level=2) - # 2. 模糊匹配(兼容 "电路施工" → "电路施工镜") + # 2. 模糊匹配 if parent is None: - parent = await broll_category.get_by_name_like_and_level( - db, name=parent_name, level=2 - ) - - # 3. 去掉常见后缀再试 - if parent is None: - for suffix in ("镜", "阶段"): - if not parent_name.endswith(suffix): - candidate = parent_name + suffix - parent = await broll_category.get_by_name_and_level( - db, name=candidate, level=2 - ) - if parent: - break + parent = await broll_category.get_by_name_like_and_level(db, name=parent_name, level=2) if parent is None: return None - children = await broll_category.get_children_by_parent_id( - db, parent_id=parent.id, level=3 - ) + children = await broll_category.get_children_by_parent_id(db, parent_id=parent.id, level=3) if not children: return None - return random.choice(children) + return random.choice(children) # nosec B311 素材抽样,非加密场景 async def match_material( @@ -161,46 +146,34 @@ async def match_material( normalized = _normalize_scene(scene) # 1. 查找三级分类(精确匹配 -> 全量内存匹配兜底 -> 顺序颠倒 -> 上级回退) - category = await broll_category.get_by_name_and_level( - db, name=normalized, level=3 - ) + category = await broll_category.get_by_name_and_level(db, name=normalized, level=3) # 精确匹配失败时,全量查询后在内存标准化匹配(兼容数据库 name 含不可见字符) if category is None: all_categories = await broll_category.get_by_level(db, level=3) for c in all_categories: if _normalize_scene(c.name) == normalized: category = c - logger.info( - f"素材分类全量内存匹配命中: '{normalized}' -> '{c.name}'" - ) + logger.info(f"素材分类全量内存匹配命中: '{normalized}' -> '{c.name}'") break # 若仍失败,尝试将 "A-B" 倒序为 "B-A" 再匹配 if category is None: parts = normalized.rsplit("-", 1) if len(parts) == 2: reversed_name = f"{parts[1]}-{parts[0]}" - category = await broll_category.get_by_name_and_level( - db, name=reversed_name, level=3 - ) + category = await broll_category.get_by_name_and_level(db, name=reversed_name, level=3) if category: - logger.info( - f"素材分类顺序颠倒兜底命中: '{normalized}' -> '{reversed_name}'" - ) + logger.info(f"素材分类顺序颠倒兜底命中: '{normalized}' -> '{reversed_name}'") # 若仍失败,回退到上级分类随机选取 if category is None: category = await _try_fallback_to_parent(db, normalized) if category: - logger.info( - f"素材回退到上级分类命中: '{normalized}' -> '{category.name}'" - ) + logger.info(f"素材回退到上级分类命中: '{normalized}' -> '{category.name}'") if category is None: logger.warning(f"素材匹配失败: 未找到分类 '{normalized}' (原始 scene: '{scene}')") return None # 2. 查询该分类下所有 active 素材(先不过滤时长,用于日志诊断) - all_materials = await broll_material.get_active_by_categories( - db, category_ids=[category.id] - ) + all_materials = await broll_material.get_active_by_categories(db, category_ids=[category.id]) if not all_materials: logger.warning(f"素材匹配失败: 分类 '{normalized}' 下无任何可用素材") return None @@ -224,7 +197,7 @@ async def match_material( try: redis = get_redis_client() key = f"proj:{project_id}:used_materials" - used_urls = set(await redis.smembers(key)) + used_urls = set(await cast(Awaitable[set[Any]], redis.smembers(key))) except Exception as e: logger.warning(f"Redis 去重查询失败,降级为不去重: {e}") @@ -243,8 +216,8 @@ async def match_material( try: redis = get_redis_client() key = f"proj:{project_id}:used_materials" - await redis.sadd(key, chosen.url) - await redis.expire(key, _USED_MATERIALS_TTL) + await cast(Awaitable[int], redis.sadd(key, chosen.url)) + await cast(Awaitable[int], redis.expire(key, _USED_MATERIALS_TTL)) except Exception as e: logger.warning(f"Redis 去重记录失败: {e}") @@ -282,10 +255,8 @@ async def batch_match( unique_names = list(set(normalized_scenes)) # 2. 批量查询分类:优先精确查询,失败时全量内存匹配兜底 - categories = await broll_category.get_by_names_and_level( - db, names=unique_names, level=3 - ) - category_map: dict[str, object] = {} + categories = await broll_category.get_by_names_and_level(db, names=unique_names, level=3) + category_map: dict[str, BrollCategory] = {} for c in categories: category_map[_normalize_scene(c.name)] = c @@ -305,16 +276,14 @@ async def batch_match( if len(parts) == 2: reversed_map[name] = f"{parts[1]}-{parts[0]}" - scene_to_category: dict[str, object] = {} + scene_to_category: dict[str, BrollCategory] = {} for name in unique_names: if name in category_map: scene_to_category[name] = category_map[name] elif name in reversed_map and reversed_map[name] in category_map: rev = reversed_map[name] scene_to_category[name] = category_map[rev] - logger.info( - f"批量匹配顺序颠倒兜底命中: '{name}' -> '{rev}'" - ) + logger.info(f"批量匹配顺序颠倒兜底命中: '{name}' -> '{rev}'") # 3. 未匹配的 scene 回退到上级分类随机选取 unmatched = [name for name in unique_names if name not in scene_to_category] @@ -322,15 +291,11 @@ async def batch_match( fallback_cat = await _try_fallback_to_parent(db, name) if fallback_cat: scene_to_category[name] = fallback_cat - logger.info( - f"批量匹配回退到上级分类命中: '{name}' -> '{fallback_cat.name}'" - ) + logger.info(f"批量匹配回退到上级分类命中: '{name}' -> '{fallback_cat.name}'") # 4. 收集所有需要的 category_id needed_category_ids = [ - scene_to_category[name].id - for name in unique_names - if name in scene_to_category + scene_to_category[name].id for name in unique_names if name in scene_to_category ] # 4. 批量查询素材(1 次 DB) @@ -339,7 +304,7 @@ async def batch_match( ) # 按 category_id 分组,方便内存过滤 - materials_by_category: dict[int, list] = {} + materials_by_category: dict[int, list[BrollMaterial]] = {} for m in all_materials: materials_by_category.setdefault(m.category_id, []).append(m) @@ -349,13 +314,13 @@ async def batch_match( try: redis = get_redis_client() key = f"proj:{project_id}:used_materials" - used_urls = set(await redis.smembers(key)) + used_urls = set(await cast(Awaitable[set[Any]], redis.smembers(key))) except Exception as e: logger.warning(f"Redis 去重查询失败,降级为不去重: {e}") # 6. 内存中逐个匹配 results: list[dict | None] = [] - chosen_materials: list = [] # 记录选中的素材,用于批量更新 + chosen_materials: list[BrollMaterial] = [] # 记录选中的素材,用于批量更新 for idx, scene_name in enumerate(normalized_scenes): required_duration = scenes[idx]["duration"] diff --git a/python-api/app/services/point_service.py b/python-api/app/services/point_service.py index 0e5d79e..709f78d 100644 --- a/python-api/app/services/point_service.py +++ b/python-api/app/services/point_service.py @@ -25,7 +25,7 @@ import logging import math from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import yaml from sqlalchemy import select @@ -33,6 +33,7 @@ from sqlalchemy.ext.asyncio import AsyncSession logger = logging.getLogger(__name__) +from app.core.exceptions import InsufficientPointsException from app.models.point_batch import PointBatch from app.models.point_transaction import PointTransaction from app.models.user_point import UserPoint @@ -46,11 +47,11 @@ if TYPE_CHECKING: _CONFIG_PATH = Path(__file__).resolve().parents[2] / "config" / "points-config.yaml" -def _load_points_config() -> dict: +def _load_points_config() -> dict[str, Any]: """加载积分计费配置。服务启动时读取一次,后续内存中使用。""" if not _CONFIG_PATH.exists(): raise FileNotFoundError(f"积分配置文件不存在: {_CONFIG_PATH}") - with open(_CONFIG_PATH, "r", encoding="utf-8") as f: + with open(_CONFIG_PATH, encoding="utf-8") as f: cfg = yaml.safe_load(f) or {} # 合并为统一的查询字典:source_type -> {"mode": "fixed|duration|free", ...} merged: dict[str, dict] = {} @@ -65,18 +66,22 @@ def _load_points_config() -> dict: return merged -POINTS_CONFIG: dict[str, dict] = _load_points_config() +POINTS_CONFIG: dict[str, Any] = _load_points_config() def get_recharge_options() -> list[dict]: """获取充值档位配置(由后端控制,支持积分赠送)""" - return POINTS_CONFIG.get("_recharge_options", []) + options = POINTS_CONFIG.get("_recharge_options", []) + if isinstance(options, list): + return options + return [] def get_chargeable_source_types() -> list[str]: """获取所有需要扣费的业务类型列表(排除免费业务)""" return [ - key for key, cfg in POINTS_CONFIG.items() + key + for key, cfg in POINTS_CONFIG.items() if not key.startswith("_") and cfg.get("mode") != "free" ] @@ -163,11 +168,10 @@ def _estimate_max_cost(source_type: str, param: dict | None = None) -> int: # ── 余额查询 ────────────────────────────────────────── + async def get_user_balance(db: AsyncSession, user_id: UUID | str) -> dict: """获取用户积分余额快照(实时计算,排除已过期批次)。""" - result = await db.execute( - select(UserPoint).where(UserPoint.user_id == user_id) - ) + result = await db.execute(select(UserPoint).where(UserPoint.user_id == user_id)) up = result.scalar_one_or_none() if not up: @@ -182,8 +186,7 @@ async def get_user_balance(db: AsyncSession, user_id: UUID | str) -> dict: from sqlalchemy import func as _func available_result = await db.execute( - select(_func.coalesce(_func.sum(PointBatch.remaining), 0)) - .where( + select(_func.coalesce(_func.sum(PointBatch.remaining), 0)).where( PointBatch.user_id == user_id, PointBatch.remaining > 0, PointBatch.expired_at > _now(), @@ -221,6 +224,7 @@ async def check_balance( # ── 充值 ────────────────────────────────────────────── + async def recharge( db: AsyncSession, *, @@ -247,8 +251,7 @@ async def recharge( # 幂等保护:同一笔订单(order_id)只能充值一次 if order_id: existing_result = await db.execute( - select(PointTransaction) - .where( + select(PointTransaction).where( PointTransaction.source_id == str(order_id), PointTransaction.type == "recharge", ) @@ -259,9 +262,7 @@ async def recharge( return existing_tx # 1. 获取或创建用户积分账户 - result = await db.execute( - select(UserPoint).where(UserPoint.user_id == user_id) - ) + result = await db.execute(select(UserPoint).where(UserPoint.user_id == user_id)) up = result.scalar_one_or_none() if not up: @@ -353,7 +354,7 @@ async def consume( 直接扣费(后置计费)。 业务执行成功后调用,按实际消耗直接扣除余额。 - 默认不允许欠费(余额不足时抛出 ValueError)。 + 默认不允许欠费(余额不足时抛出 InsufficientPointsException)。 Scheduler 后置扣费等场景可设置 allow_negative=True,允许余额变负。 :param points: 实际消耗积分(正整数) @@ -383,9 +384,7 @@ async def consume( # 2. 获取用户积分账户(加锁) result = await db.execute( - select(UserPoint) - .where(UserPoint.user_id == user_id) - .with_for_update() + select(UserPoint).where(UserPoint.user_id == user_id).with_for_update() ) up = result.scalar_one_or_none() @@ -404,7 +403,7 @@ async def consume( # 3. 余额检查:用实时可用余额(未过期批次 remaining 总和),避免 expire_batches 延迟导致超扣 available = sum(b.remaining for b in batches) if not allow_negative and available < points: - raise ValueError(f"积分不足,当前可用余额 {available},需要 {points} 积分") + raise InsufficientPointsException(f"积分不足,当前可用余额 {available},需要 {points} 积分") remaining_to_deduct = points for batch in batches: @@ -440,6 +439,7 @@ async def consume( # ── 过期回收 ────────────────────────────────────────── + async def expire_batches(db: AsyncSession) -> int: """ 回收过期积分批次。返回过期积分总数。 @@ -468,9 +468,7 @@ async def expire_batches(db: AsyncSession) -> int: # 获取用户积分账户(加锁) up_result = await db.execute( - select(UserPoint) - .where(UserPoint.user_id == batch.user_id) - .with_for_update() + select(UserPoint).where(UserPoint.user_id == batch.user_id).with_for_update() ) up = up_result.scalar_one_or_none() if not up: diff --git a/python-api/app/services/qiniu_service.py b/python-api/app/services/qiniu_service.py index 2e6c68c..13508ca 100644 --- a/python-api/app/services/qiniu_service.py +++ b/python-api/app/services/qiniu_service.py @@ -104,7 +104,9 @@ class QiniuService: # 项目前缀 PROJECT_PREFIX = "meijiaka-zy" - def generate_key(self, file_type: str, original_filename: str, user_id: str = None) -> str: + def generate_key( + self, file_type: str, original_filename: str, user_id: str | None = None + ) -> str: """ 生成规范的文件存储路径 @@ -143,7 +145,7 @@ class QiniuService: return mime_type in allowed_types def get_upload_token( - self, bucket: str, key: str, expires: int = 3600, policy: dict = None + self, bucket: str, key: str, expires: int = 3600, policy: dict | None = None ) -> str: """ 生成上传凭证(客户端直传使用) @@ -197,9 +199,9 @@ class QiniuService: def upload_file( self, local_path: str, - key: str = None, + key: str | None = None, file_type: str = "audio", - user_id: str = None, + user_id: str | None = None, check_duplicate: bool = True, ) -> dict: """ @@ -222,15 +224,15 @@ class QiniuService: "is_duplicate": 是否复用已有文件 } """ - local_path = Path(local_path) - if not local_path.exists(): - raise FileNotFoundError(f"文件不存在: {local_path}") + local_path_obj = Path(local_path) + if not local_path_obj.exists(): + raise FileNotFoundError(f"文件不存在: {local_path_obj}") # 根据文件类型获取对应的 bucket 和 domain bucket, domain = self._get_bucket_and_domain(file_type) # 计算文件 MD5 哈希 - file_md5 = self._calculate_file_hash(local_path) + file_md5 = self._calculate_file_hash(local_path_obj) # 检查是否已存在相同文件 if check_duplicate: @@ -248,20 +250,20 @@ class QiniuService: # 自动生成 Key if key is None: - key = self.generate_key(file_type, local_path.name, user_id) + key = self.generate_key(file_type, local_path_obj.name, user_id) # 生成上传 Token token = self.get_upload_token(bucket, key) # 使用分片上传 - ret, info = put_file(up_token=token, key=key, file_path=str(local_path)) + ret, info = put_file(up_token=token, key=key, file_path=str(local_path_obj)) if ret is None: raise Exception(f"上传失败: {info}") # 获取文件信息 - mime_type, _ = mimetypes.guess_type(str(local_path)) - fsize = local_path.stat().st_size + mime_type, _ = mimetypes.guess_type(str(local_path_obj)) + fsize = local_path_obj.stat().st_size return { "key": ret["key"], @@ -277,8 +279,8 @@ class QiniuService: stream: BinaryIO, key: str, mime_type: str = "application/octet-stream", - bucket: str = None, - domain: str = None, + bucket: str | None = None, + domain: str | None = None, ) -> dict: """ 上传文件流到七牛云 @@ -317,7 +319,9 @@ class QiniuService: return {"key": ret["key"], "hash": ret["hash"], "url": self.get_file_url(domain, key)} - def upload_audio(self, local_path: str, user_id: str = None, key: str = None) -> dict: + def upload_audio( + self, local_path: str, user_id: str | None = None, key: str | None = None + ) -> dict: """ 上传音频文件(专用接口) @@ -336,7 +340,9 @@ class QiniuService: return self.upload_file(local_path=local_path, key=key, file_type="audio", user_id=user_id) - def upload_video(self, local_path: str, user_id: str = None, key: str = None) -> dict: + def upload_video( + self, local_path: str, user_id: str | None = None, key: str | None = None + ) -> dict: """ 上传视频文件(专用接口) @@ -454,9 +460,9 @@ class QiniuService: async def upload_file_async( self, local_path: str, - key: str = None, + key: str | None = None, file_type: str = "audio", - user_id: str = None, + user_id: str | None = None, check_duplicate: bool = True, ) -> dict: """异步版本 upload_file""" @@ -469,19 +475,21 @@ class QiniuService: stream: BinaryIO, key: str, mime_type: str = "application/octet-stream", - bucket: str = None, - domain: str = None, + bucket: str | None = None, + domain: str | None = None, ) -> dict: """异步版本 upload_stream""" - return await asyncio.to_thread( - self.upload_stream, stream, key, mime_type, bucket, domain - ) + return await asyncio.to_thread(self.upload_stream, stream, key, mime_type, bucket, domain) - async def upload_audio_async(self, local_path: str, user_id: str = None, key: str = None) -> dict: + async def upload_audio_async( + self, local_path: str, user_id: str | None = None, key: str | None = None + ) -> dict: """异步版本 upload_audio""" return await asyncio.to_thread(self.upload_audio, local_path, user_id, key) - async def upload_video_async(self, local_path: str, user_id: str = None, key: str = None) -> dict: + async def upload_video_async( + self, local_path: str, user_id: str | None = None, key: str | None = None + ) -> dict: """异步版本 upload_video""" return await asyncio.to_thread(self.upload_video, local_path, user_id, key) diff --git a/python-api/app/services/script_service.py b/python-api/app/services/script_service.py index 49aa4b1..60f58d5 100644 --- a/python-api/app/services/script_service.py +++ b/python-api/app/services/script_service.py @@ -7,9 +7,16 @@ import asyncio import logging import time from pathlib import Path +from typing import Any from app.ai.model_router import get_model_router from app.ai.prompts import load_prompt_file, load_script_user_prompt +from app.core.exceptions import ( + AIEmptyResponseException, + AIParseErrorException, + AITimeoutException, + PromptNotFoundException, +) from app.schemas.script import ScriptShot from app.services.ai_response_utils import ( safe_parse_ai_json_response, @@ -22,12 +29,9 @@ logger = logging.getLogger(__name__) class ScriptService: """脚本生成服务""" - def __init__(self): self.prompts_dir = Path(__file__).parent.parent / "ai" / "prompts" - - def _load_prompt(self, name: str) -> str: """加载 Prompt 模板""" prompt_file = self.prompts_dir / f"{name}.txt" @@ -58,7 +62,7 @@ class ScriptService: # 加载 Prompt system_prompt = load_prompt_file(category, filename) if not system_prompt: - raise ValueError(f"未找到提示词: category={category}, filename={filename}") + raise PromptNotFoundException(f"未找到提示词: category={category}, filename={filename}") # 用户提示词 user_prompt = load_script_user_prompt( @@ -75,24 +79,26 @@ class ScriptService: ) if not result.content or not result.content.strip(): - raise ValueError("AI 返回内容为空,请检查模型配置或重试") + raise AIEmptyResponseException("AI 返回内容为空,请检查模型配置或重试") success, parsed_data, error_msg = safe_parse_ai_json_response(result.content) if not success: - raise ValueError(error_msg or "AI 返回格式错误,无法解析为 JSON") + raise AIParseErrorException(error_msg or "AI 返回格式错误,无法解析为 JSON") try: shots_data = validate_and_normalize_shots(parsed_data) if not shots_data: - raise ValueError("AI 返回的分镜数据为空或格式不正确") + raise AIEmptyResponseException("AI 返回的分镜数据为空或格式不正确") shots = [ScriptShot(**shot) for shot in shots_data] return shots + except (AIEmptyResponseException, AIParseErrorException): + raise except Exception as e: - raise ValueError(f"分镜数据处理失败: {str(e)}") + raise AIParseErrorException(f"分镜数据处理失败: {str(e)}") async def polish_content( self, @@ -144,21 +150,23 @@ class ScriptService: ) return result.content.strip() except TimeoutError: - raise ValueError("润色请求超时,请重试") + raise AITimeoutException("润色请求超时,请重试") + except (AIEmptyResponseException, AIParseErrorException, AITimeoutException): + raise except Exception as e: - raise ValueError(f"润色失败: {str(e)}") + raise AIParseErrorException(f"润色失败: {str(e)}") async def check_model_health(self) -> dict: """检查模型健康状态""" model_router = await get_model_router() health_results = await model_router.health_check() - models = [] + models: list[dict[str, Any]] = [] available_count = 0 - recommended = None + recommended: dict[str, Any] | None = None for _provider_id, health in health_results.items(): - model_info = { + model_info: dict[str, Any] = { "id": health.id, "name": health.name, "is_available": health.is_available, @@ -169,9 +177,12 @@ class ScriptService: if health.is_available: available_count += 1 - if recommended is None or health.response_time < recommended.get( - "response_time", float("inf") - ): + current_best = ( + float("inf") + if recommended is None + else float(recommended.get("response_time") or float("inf")) + ) + if health.response_time < current_best: recommended = model_info total = len(models) @@ -188,7 +199,6 @@ class ScriptService: """测试指定模型连接""" model_router = await get_model_router() - start_time = time.time() try: diff --git a/python-api/app/services/sms_service.py b/python-api/app/services/sms_service.py index d84a0a3..d7bf8cd 100644 --- a/python-api/app/services/sms_service.py +++ b/python-api/app/services/sms_service.py @@ -76,9 +76,7 @@ class B2MSMSService: if self.secret_key: key_bytes = self.secret_key.encode("utf-8") if len(key_bytes) not in (16, 24, 32): - raise SMSError( - f"AES 密钥长度必须是 16/24/32 字节,当前 {len(key_bytes)} 字节" - ) + raise SMSError(f"AES 密钥长度必须是 16/24/32 字节,当前 {len(key_bytes)} 字节") self._secret_key_bytes = key_bytes if not all([self.app_id, self.secret_key, self.base_url]): @@ -245,6 +243,7 @@ class B2MSMSService: # ── 便捷函数 ────────────────────────────────────────── + def get_sms_service() -> B2MSMSService: """获取短信服务实例""" return B2MSMSService() diff --git a/python-api/app/services/vidu_service.py b/python-api/app/services/vidu_service.py index 054823f..61bbdcd 100644 --- a/python-api/app/services/vidu_service.py +++ b/python-api/app/services/vidu_service.py @@ -207,8 +207,9 @@ class ViduService: error_type=PlatformErrorType.BAD_REQUEST, ) - logger.info(f"[Vidu Clone] 复刻成功: voice_id={result.data.get('voice_id')}") - return result.data or {} + clone_data = result.data or {} + logger.info(f"[Vidu Clone] 复刻成功: voice_id={clone_data.get('voice_id')}") + return clone_data async def query_clone_task(self, voice_id: str) -> dict[str, Any]: """Vidu 声音复刻是同步接口,无独立查询。 @@ -270,6 +271,8 @@ class ViduService: result_data = status.result or {} return { "state": ViduAdapter.denormalize_state(status.state), - "creations": [{"url": result_data.get("video_url")}] if result_data.get("video_url") else [], + "creations": ( + [{"url": result_data.get("video_url")}] if result_data.get("video_url") else [] + ), "message": status.error_message, } diff --git a/python-api/app/services/volcengine_caption_service.py b/python-api/app/services/volcengine_caption_service.py index 83f59b4..9a565a5 100644 --- a/python-api/app/services/volcengine_caption_service.py +++ b/python-api/app/services/volcengine_caption_service.py @@ -155,10 +155,7 @@ class VolcengineCaptionService: error_type=PlatformErrorType.BAD_REQUEST, ) - logger.warning( - f"{task_name}超过最大轮询次数: task_id={task_id}, " - f"retries={retries}" - ) + logger.warning(f"{task_name}超过最大轮询次数: task_id={task_id}, " f"retries={retries}") raise PlatformError( f"{task_name}超时,请稍后重试", platform="volcengine_caption", diff --git a/python-api/app/services/volcengine_mediakit_service.py b/python-api/app/services/volcengine_mediakit_service.py index 94a4bfb..91a873f 100644 --- a/python-api/app/services/volcengine_mediakit_service.py +++ b/python-api/app/services/volcengine_mediakit_service.py @@ -78,9 +78,7 @@ class VolcengineMediakitService: ) if not response.success: - raise RuntimeError( - response.error_message or "抠图失败" - ) + raise RuntimeError(response.error_message or "抠图失败") result_image_url = (response.data or {}).get("image_url", "") return RemoveBackgroundResult( diff --git a/python-api/app/services/wxpay_service.py b/python-api/app/services/wxpay_service.py index 7f12e99..cc8dfbb 100644 --- a/python-api/app/services/wxpay_service.py +++ b/python-api/app/services/wxpay_service.py @@ -69,7 +69,9 @@ class WechatPayService: self.notify_url = settings.WXPAY_NOTIFY_URL if not all([self.mchid, self.appid, self.api_key]): - raise WechatPayError("微信支付配置不完整:WXPAY_MCHID / WXPAY_APPID / WXPAY_API_KEY 未配置") + raise WechatPayError( + "微信支付配置不完整:WXPAY_MCHID / WXPAY_APPID / WXPAY_API_KEY 未配置" + ) # ── 签名与验签 ────────────────────────────────────── @@ -85,7 +87,9 @@ class WechatPayService: 5. MD5 加密,结果转大写 """ # 过滤空值和 sign - filtered = {k: str(v) for k, v in params.items() if v is not None and v != "" and k != "sign"} + filtered = { + k: str(v) for k, v in params.items() if v is not None and v != "" and k != "sign" + } # ASCII 升序排序 sorted_items = sorted(filtered.items(), key=lambda x: x[0]) # 拼接字符串 diff --git a/python-api/app/utils/audio_utils.py b/python-api/app/utils/audio_utils.py index e653681..ae1f4d8 100644 --- a/python-api/app/utils/audio_utils.py +++ b/python-api/app/utils/audio_utils.py @@ -41,13 +41,15 @@ async def get_audio_duration(url: str, timeout: float = 10.0) -> float: try: if header[:3] == b"ID3" or header[:2] == b"\xff\xfb" or header[:2] == b"\xff\xf3": - audio = MP3(data) + audio: MP3 | WAVE = MP3(data) elif header[:4] == b"RIFF": audio = WAVE(data) else: # fallback:先尝试 MP3(大多数 TTS 返回 mp3) audio = MP3(data) + if audio.info is None: + raise ValueError("音频信息解析失败") duration = audio.info.length if duration is None or duration <= 0: raise ValueError("音频时长解析失败") diff --git a/python-api/app/utils/content_fingerprint.py b/python-api/app/utils/content_fingerprint.py new file mode 100644 index 0000000..099f64b --- /dev/null +++ b/python-api/app/utils/content_fingerprint.py @@ -0,0 +1,133 @@ +""" +内容指纹工具 +============ + +用于 AI 第三方平台(如 Vidu)的审核结果缓存与防重复提交。 + +核心逻辑: +- 对提交的音频/视频/图片 URL + 任务参数生成 SHA256 指纹。 +- 如果相同内容近期因审核失败被缓存,则直接返回错误,不再调用第三方平台。 +- 仅规范化 URL(去掉 token 等动态参数),不下载大文件本身。 +""" + +from __future__ import annotations + +import hashlib +from urllib.parse import parse_qs, urlencode, urlparse + +# Vidu 内容安全/审核类错误码 +# 这些错误在内容不变的情况下重试也没用,应该被缓存。 +VIDU_AUDIT_ERROR_CODES = frozenset( + { + "TaskPromptPolicyViolation", # Prompt 触发安审风控 + "AuditSubmitIllegal", # 输入未通过安全审核 + "CreationPolicyViolation", # 生成物触发风控 + "PhotoAuditNotPass", # 图片审核不通过 + "AuditFailed", # 审核失败 + "ImageCheckBodyJointsFailed", # 输入图人体检测失败 + "ImageCheckFaceFailed", # 输入图人脸检测失败 + "ImageObjectsUndetected", # 人体或人脸有遮挡 + "FaceDetectFailure", # 人脸检测失败 + "FaceDetectNotPass", # 人脸检测不通过 + "NoFaceDetected", # 未检测到人脸 + "MultiFaceDetected", # 检测到多张人脸 + } +) + + +# 常见动态 query 参数,生成指纹时应忽略 +_DYNAMIC_QUERY_PARAMS = frozenset( + { + "token", + "e", # 七牛过期时间戳 + "t", # 时间戳 + "sign", + "x-oss-signature", + "x-oss-expires", + "x-oss-access-key-id", + "response-content-disposition", + "v", # 版本号/缓存戳 + } +) + + +def normalize_url(url: str | None) -> str: + """规范化 URL,去掉动态参数,确保同一资源不同 token 得到相同指纹。 + + Args: + url: 原始 URL,可能包含七牛私有 token、时间戳等动态参数 + + Returns: + 规范化后的 URL 字符串,None 或空字符串返回空串 + """ + if not url: + return "" + + parsed = urlparse(url) + query_params = parse_qs(parsed.query, keep_blank_values=True) + + for key in list(query_params.keys()): + if key.lower() in _DYNAMIC_QUERY_PARAMS: + del query_params[key] + + query = urlencode(sorted(query_params.items()), doseq=True) + path = parsed.path or "/" + + if query: + return f"{parsed.scheme}://{parsed.netloc}{path}?{query}" + return f"{parsed.scheme}://{parsed.netloc}{path}" + + +def compute_content_fingerprint( + task_type: str, + *, + video_url: str | None = None, + audio_url: str | None = None, + ref_photo_url: str | None = None, + text: str | None = None, + voice_id: str | None = None, +) -> str: + """计算内容指纹。 + + 指纹字段选择原则:只包含会影响 Vidu 审核结果的输入内容。 + 不包含 callback_url、speed、volume、payload 等业务/技术参数。 + + Args: + task_type: 任务类型,如 "lip_sync", "tts", "clone_voice" + video_url: 视频 URL + audio_url: 音频 URL + ref_photo_url: 参考图片 URL + text: 文本/Prompt + voice_id: 音色 ID + + Returns: + SHA256 十六进制指纹字符串 + """ + parts = [ + task_type.strip().lower(), + normalize_url(video_url), + normalize_url(audio_url), + normalize_url(ref_photo_url), + (text or "").strip(), + (voice_id or "").strip().lower(), + ] + raw = "|".join(parts) + return hashlib.sha256(raw.encode("utf-8")).hexdigest() + + +def is_vidu_audit_error(err_code: str | None) -> bool: + """判断是否为 Vidu 审核类错误码。""" + if not err_code: + return False + return err_code.strip() in VIDU_AUDIT_ERROR_CODES + + +def extract_vidu_error_code(message: str | None) -> str | None: + """从 Vidu 错误信息中提取错误码。 + + Vidu 错误信息格式通常为:"ErrorCode: 中文描述" + """ + if not message: + return None + candidate = message.split(":")[0].strip() + return candidate or None diff --git a/python-api/app/utils/file_validation.py b/python-api/app/utils/file_validation.py index f314b09..b640cfb 100644 --- a/python-api/app/utils/file_validation.py +++ b/python-api/app/utils/file_validation.py @@ -16,9 +16,9 @@ def validate_file_magic(content: bytes, expected_content_type: str) -> bool: # 拒绝常见危险文件头 dangerous_signatures = [ - (b"MZ", "Windows 可执行文件"), # .exe, .dll - (b"#!", "Shell 脚本"), # bash, python, etc - (b"PK\x03\x04", "ZIP 压缩包"), # .zip, .jar, .docx + (b"MZ", "Windows 可执行文件"), # .exe, .dll + (b"#!", "Shell 脚本"), # bash, python, etc + (b"PK\x03\x04", "ZIP 压缩包"), # .zip, .jar, .docx (b"=0.136.1", + "fastapi>=0.115.8", "uvicorn[standard]~=0.32.0", - "python-multipart~=0.0.20", - + "python-multipart>=0.0.27", + "pyasn1>=0.6.3", # 安全修复:间接依赖,强制升级 + # 认证 & 安全 "passlib[bcrypt]~=1.7.4", "bcrypt~=4.2.0", @@ -47,14 +48,14 @@ dependencies = [ "volcengine-python-sdk[ark]~=5.0.0", # HTTP 客户端 - "httpx~=0.28.0", - "aiohttp>=3.13.4", # 安全修复:修复 CVE-2025-XXXX 系列漏洞 + "httpx>=0.28.0", + "aiohttp>=3.14.0", # 安全修复:修复 CVE-2025-XXXX 系列漏洞 # 对象存储 "qiniu~=7.13.0", # 工具 - "pyjwt~=2.10.0", + "pyjwt>=2.13.0", "pyyaml~=6.0.2", "orjson>=3.11.0", # 安全修复:修复 CVE-2025-XXXX @@ -68,12 +69,12 @@ dependencies = [ [project.optional-dependencies] dev = [ - "pytest~=8.3.0", - "pytest-asyncio~=0.24.0", - "pytest-cov~=6.0.0", - "ruff~=0.8.0", - "black~=24.10.0", - "mypy~=1.14.0", + "pytest>=9.0.3", + "pytest-asyncio>=0.24.0", + "pytest-cov>=6.0.0", + "ruff>=0.8.0", + "black>=26.3.1", + "mypy>=1.14.0", "bandit[toml]~=1.8.0", # 安全扫描 "pip-audit~=2.7.0", # 漏洞检测 "pre-commit~=4.0.0", # Git 钩子 @@ -99,7 +100,6 @@ ignore = ["E501", "E402", "N802", "N803", "N806", "N815", "B008", "B904"] [tool.mypy] python_version = "3.13" -strict = false warn_return_any = false warn_unused_configs = true ignore_missing_imports = true @@ -112,7 +112,6 @@ disallow_incomplete_defs = false # ========== 重构防护网:新代码严格模式 ========== [[tool.mypy.overrides]] module = ["app.schemas.*", "app.crud.*", "app.scheduler.handlers.*"] -strict = true warn_return_any = true check_untyped_defs = true disallow_untyped_defs = true @@ -121,7 +120,6 @@ disallow_incomplete_defs = true # Redis 客户端 typing 问题(Awaitable[T] | T),暂不严格检查 [[tool.mypy.overrides]] module = ["app.scheduler.registry", "app.scheduler.slot_manager"] -strict = false check_untyped_defs = false disallow_untyped_defs = false diff --git a/python-api/requirements.lock b/python-api/requirements.lock index 217c020..3931552 100644 --- a/python-api/requirements.lock +++ b/python-api/requirements.lock @@ -1,8 +1,8 @@ # This file was autogenerated by uv via the following command: # uv pip compile pyproject.toml -o requirements.lock -aiohappyeyeballs==2.6.1 +aiohappyeyeballs==2.6.2 # via aiohttp -aiohttp==3.13.5 +aiohttp==3.14.1 # via meijiaka-ai-api (pyproject.toml) aiosignal==1.4.0 # via aiohttp @@ -27,7 +27,7 @@ bcrypt==4.2.1 # via # meijiaka-ai-api (pyproject.toml) # passlib -certifi==2026.4.22 +certifi==2026.5.20 # via # httpcore # httpx @@ -37,19 +37,19 @@ cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -click==8.3.3 +click==8.4.1 # via uvicorn -cryptography==48.0.0 +cryptography==48.0.1 # via volcengine-python-sdk distro==1.9.0 # via openai -fastapi==0.136.1 +fastapi==0.136.3 # via meijiaka-ai-api (pyproject.toml) frozenlist==1.8.0 # via # aiohttp # aiosignal -greenlet==3.5.0 +greenlet==3.5.1 # via sqlalchemy h11==0.16.0 # via @@ -57,20 +57,20 @@ h11==0.16.0 # uvicorn httpcore==1.0.9 # via httpx -httptools==0.7.1 +httptools==0.8.0 # via uvicorn httpx==0.28.1 # via # meijiaka-ai-api (pyproject.toml) # openai # volcengine-python-sdk -idna==3.13 +idna==3.18 # via # anyio # httpx # requests # yarl -jiter==0.14.0 +jiter==0.15.0 # via openai mako==1.3.12 # via alembic @@ -88,12 +88,16 @@ orjson==3.11.9 # via meijiaka-ai-api (pyproject.toml) passlib==1.7.4 # via meijiaka-ai-api (pyproject.toml) -propcache==0.4.1 +pillow==12.2.0 + # via meijiaka-ai-api (pyproject.toml) +propcache==0.5.2 # via # aiohttp # yarl psycopg2-binary==2.9.12 # via meijiaka-ai-api (pyproject.toml) +pyasn1==0.6.3 + # via meijiaka-ai-api (pyproject.toml) pycparser==3.0 # via cffi pydantic==2.9.2 @@ -107,7 +111,7 @@ pydantic-core==2.23.4 # via pydantic pydantic-settings==2.6.1 # via meijiaka-ai-api (pyproject.toml) -pyjwt==2.10.1 +pyjwt==2.13.0 # via meijiaka-ai-api (pyproject.toml) python-dateutil==2.9.0.post0 # via volcengine-python-sdk @@ -115,7 +119,7 @@ python-dotenv==1.2.2 # via # pydantic-settings # uvicorn -python-multipart==0.0.27 +python-multipart==0.0.32 # via meijiaka-ai-api (pyproject.toml) pyyaml==6.0.3 # via @@ -125,7 +129,7 @@ qiniu==7.13.2 # via meijiaka-ai-api (pyproject.toml) redis==5.2.1 # via meijiaka-ai-api (pyproject.toml) -requests==2.33.1 +requests==2.34.2 # via qiniu six==1.17.0 # via @@ -133,15 +137,15 @@ six==1.17.0 # volcengine-python-sdk sniffio==1.3.1 # via openai -sqlalchemy==2.0.49 +sqlalchemy==2.0.50 # via # meijiaka-ai-api (pyproject.toml) # alembic -starlette==1.0.0 +starlette==1.3.0 # via fastapi tenacity==9.0.0 # via meijiaka-ai-api (pyproject.toml) -tqdm==4.67.3 +tqdm==4.68.2 # via openai typing-extensions==4.15.0 # via @@ -162,11 +166,11 @@ uvicorn==0.32.1 # via meijiaka-ai-api (pyproject.toml) uvloop==0.22.1 # via uvicorn -volcengine-python-sdk==5.0.26 +volcengine-python-sdk==5.0.34 # via meijiaka-ai-api (pyproject.toml) -watchfiles==1.1.1 +watchfiles==1.2.0 # via uvicorn websockets==16.0 # via uvicorn -yarl==1.23.0 +yarl==1.24.2 # via aiohttp diff --git a/python-api/tests/__init__.py b/python-api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python-api/tests/test_exceptions.py b/python-api/tests/test_exceptions.py new file mode 100644 index 0000000..8c80f48 --- /dev/null +++ b/python-api/tests/test_exceptions.py @@ -0,0 +1,116 @@ +""" +异常体系单元测试 +================ + +验证 AppException / InsufficientPointsException 的结构化字段, +确保前端可以通过 error_code 识别错误类型。 +""" + +from fastapi import HTTPException + +from app.core.exceptions import ( + AIEmptyResponseException, + AIParseErrorException, + AITimeoutException, + AppException, + BusinessException, + InsufficientPointsException, + NotFoundException, + PromptNotFoundException, + ValidationException, +) + + +class TestAppException: + """业务异常基类""" + + def test_app_exception_has_error_code(self) -> None: + exc = AppException( + status_code=400, + message="参数错误", + error_code="validation_error", + ) + assert exc.status_code == 400 + assert exc.message == "参数错误" + assert exc.error_code == "validation_error" + assert exc.detail == {"message": "参数错误", "error_code": "validation_error"} + + def test_app_exception_detail_can_be_dict(self) -> None: + exc = AppException( + status_code=422, + message="字段校验失败", + detail={"fields": {"name": "required"}}, + error_code="validation_error", + ) + assert exc.detail == { + "fields": {"name": "required"}, + "message": "字段校验失败", + "error_code": "validation_error", + } + + def test_subclasses_without_error_code(self) -> None: + exc = NotFoundException("资源不存在") + assert exc.status_code == 404 + assert exc.message == "资源不存在" + assert exc.error_code is None + + +class TestInsufficientPointsException: + """积分不足异常""" + + def test_default_fields(self) -> None: + exc = InsufficientPointsException() + assert exc.status_code == 402 + assert exc.message == "积分不足" + assert exc.error_code == "insufficient_points" + assert isinstance(exc, HTTPException) + + def test_custom_message(self) -> None: + exc = InsufficientPointsException("余额不足,请先充值") + assert exc.message == "余额不足,请先充值" + assert exc.error_code == "insufficient_points" + + def test_detail_structure(self) -> None: + exc = InsufficientPointsException("需要 10 积分") + assert exc.detail == { + "message": "需要 10 积分", + "error_code": "insufficient_points", + } + + +class TestOtherSubclasses: + """其他常用子类""" + + def test_validation_exception(self) -> None: + exc = ValidationException("字段缺失") + assert exc.status_code == 422 + assert exc.message == "字段缺失" + + def test_business_exception(self) -> None: + exc = BusinessException("业务状态不允许") + assert exc.status_code == 400 + assert exc.message == "业务状态不允许" + + +class TestAIStructuredExceptions: + """AI 相关结构化异常""" + + def test_prompt_not_found_exception(self) -> None: + exc = PromptNotFoundException("未找到提示词") + assert exc.status_code == 404 + assert exc.error_code == "prompt_not_found" + + def test_ai_empty_response_exception(self) -> None: + exc = AIEmptyResponseException("AI 返回为空") + assert exc.status_code == 500 + assert exc.error_code == "empty_result" + + def test_ai_parse_error_exception(self) -> None: + exc = AIParseErrorException("解析失败") + assert exc.status_code == 500 + assert exc.error_code == "parse_error" + + def test_ai_timeout_exception(self) -> None: + exc = AITimeoutException("请求超时") + assert exc.status_code == 504 + assert exc.error_code == "timeout" diff --git a/python-api/tests/test_point_service.py b/python-api/tests/test_point_service.py new file mode 100644 index 0000000..216eef1 --- /dev/null +++ b/python-api/tests/test_point_service.py @@ -0,0 +1,95 @@ +""" +积分 Service 单元测试 +===================== + +不依赖数据库,仅测试配置加载、计费计算、充值档位等纯函数逻辑。 +""" + +import math + +import pytest + +from app.services import point_service as ps + + +class TestPointsConfig: + """积分配置加载""" + + def test_points_config_loaded(self) -> None: + assert "script" in ps.POINTS_CONFIG + assert "tts" in ps.POINTS_CONFIG + assert "video" in ps.POINTS_CONFIG + + def test_get_chargeable_source_types(self) -> None: + types = ps.get_chargeable_source_types() + assert "script" in types + assert "tts" in types + # 免费业务不应出现在扣费列表 + assert "caption" not in types + + def test_get_recharge_options_returns_list(self) -> None: + options = ps.get_recharge_options() + assert isinstance(options, list) + if options: + assert "points" in options[0] + + +class TestCalculateCost: + """后置计费计算""" + + def test_fixed_cost(self) -> None: + assert ps._calculate_cost("script") == 5 + assert ps._calculate_cost("polish") == 1 + assert ps._calculate_cost("voice_clone") == 200 + + def test_free_cost(self) -> None: + free_types = [ + key + for key, cfg in ps.POINTS_CONFIG.items() + if not key.startswith("_") and cfg.get("mode") == "free" + ] + for source_type in free_types: + assert ps._calculate_cost(source_type) == 0 + + def test_unknown_source_type(self) -> None: + with pytest.raises(ValueError, match="未知的消费类型"): + ps._calculate_cost("not_exists") + + def test_tts_duration_cost(self) -> None: + # tts: divisor=5,按 5 秒为单位计费 + assert ps._calculate_cost("tts", {"seconds": 4}) == 1 + assert ps._calculate_cost("tts", {"seconds": 5}) == 1 + assert ps._calculate_cost("tts", {"seconds": 6}) == 2 + assert ps._calculate_cost("tts", {"seconds": 5.1}) == 2 + + def test_video_duration_cost(self) -> None: + # video: multiplier=1,按秒向上取整 + assert ps._calculate_cost("video", {"seconds": 10}) == 10 + assert ps._calculate_cost("video", {"seconds": 10.2}) == 11 + + +class TestEstimateMaxCost: + """预估上限计算""" + + def test_tts_estimate_by_char_count(self) -> None: + cfg = ps.POINTS_CONFIG["tts"] + seconds_per_char = cfg["estimation"]["seconds_per_char"] + char_count = 100 + estimated_seconds = char_count * seconds_per_char + expected = max( + cfg["min_points"], + math.ceil(estimated_seconds / cfg["divisor"]), + ) + result = ps._estimate_max_cost("tts", {"char_count": char_count}) + assert result == expected + + def test_video_estimate_by_input_seconds(self) -> None: + with pytest.raises(ValueError, match="input_seconds"): + ps._estimate_max_cost("video", {}) + + assert ps._estimate_max_cost("video", {"input_seconds": 10}) == 10 + assert ps._estimate_max_cost("video", {"input_seconds": 10.2}) == 11 + + def test_unknown_source_type(self) -> None: + with pytest.raises(ValueError, match="未知的消费类型"): + ps._estimate_max_cost("not_exists") diff --git a/python-api/tests/test_schemas.py b/python-api/tests/test_schemas.py new file mode 100644 index 0000000..cb8bd18 --- /dev/null +++ b/python-api/tests/test_schemas.py @@ -0,0 +1,73 @@ +""" +通用 Schema 单元测试 +===================== + +验证 ApiResponse / ApiErrorResponse 的序列化与泛型行为。 +""" + +from app.schemas.common import ( + ApiErrorResponse, + ApiResponse, + error_response, + success_response, +) + + +class TestSuccessResponse: + """成功响应构造""" + + def test_success_response_with_data(self) -> None: + resp = success_response(data={"id": 1}, message="创建成功") + assert resp.code == 200 + assert resp.data == {"id": 1} + assert resp.message == "创建成功" + + def test_success_response_default(self) -> None: + resp = success_response() + assert resp.code == 200 + assert resp.data is None + assert resp.message == "success" + + +class TestErrorResponse: + """错误响应构造""" + + def test_error_response_with_error_code(self) -> None: + resp = error_response( + code=402, + message="积分不足", + error_code="insufficient_points", + ) + assert resp.code == 402 + assert resp.message == "积分不足" + assert resp.error_code == "insufficient_points" + assert resp.detail is None + + def test_error_response_with_detail(self) -> None: + resp = error_response( + code=422, + message="参数错误", + detail={"fields": {"name": "required"}}, + ) + assert resp.detail == {"fields": {"name": "required"}} + + +class TestApiResponseSerialization: + """序列化""" + + def test_api_response_model_dump(self) -> None: + resp = ApiResponse(code=200, data=[1, 2, 3], message="ok") + dumped = resp.model_dump() + assert dumped["code"] == 200 + assert dumped["data"] == [1, 2, 3] + assert dumped["message"] == "ok" + + def test_api_error_response_model_dump(self) -> None: + resp = ApiErrorResponse( + code=402, + message="积分不足", + error_code="insufficient_points", + ) + dumped = resp.model_dump() + assert dumped["code"] == 402 + assert dumped["error_code"] == "insufficient_points" diff --git a/python-api/uv.lock b/python-api/uv.lock index b8d8882..378476d 100644 --- a/python-api/uv.lock +++ b/python-api/uv.lock @@ -1,19 +1,23 @@ version = 1 revision = 3 requires-python = ">=3.13" +resolution-markers = [ + "python_full_version >= '3.15'", + "python_full_version < '3.15'", +] [[package]] name = "aiohappyeyeballs" -version = "2.6.1" +version = "2.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +sdist = { url = "https://files.pythonhosted.org/packages/33/c6/61a2d7b7572279226bb2e7f61d7a19ca7c90da0329c93fa0d560cbf288d8/aiohappyeyeballs-2.6.2.tar.gz", hash = "sha256:e202810ee718bd01fc6ef49e8ea53d023d5cb6b581076d7925aa499fa55dbe64", size = 22591, upload-time = "2026-05-20T15:12:24.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, + { url = "https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl", hash = "sha256:4708045e2d7a6c6bdf8aafa8ed39649eaf926a4543b54560659129e3365953c4", size = 15062, upload-time = "2026-05-20T15:12:23.328Z" }, ] [[package]] name = "aiohttp" -version = "3.13.5" +version = "3.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -24,59 +28,72 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/78/8ea7308cac6934de8c74a14f3d5f65d1c89287426688be79538d0e5c013d/aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035", size = 7955794, upload-time = "2026-06-07T21:09:35.529Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/e9/d76bf503005709e390122d34e15256b88f7008e246c4bdbe915cd4f1adce/aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61", size = 742930, upload-time = "2026-03-31T21:58:13.155Z" }, - { url = "https://files.pythonhosted.org/packages/57/00/4b7b70223deaebd9bb85984d01a764b0d7bd6526fcdc73cca83bcbe7243e/aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832", size = 496927, upload-time = "2026-03-31T21:58:15.073Z" }, - { url = "https://files.pythonhosted.org/packages/9c/f5/0fb20fb49f8efdcdce6cd8127604ad2c503e754a8f139f5e02b01626523f/aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9", size = 497141, upload-time = "2026-03-31T21:58:17.009Z" }, - { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e5/4e161f84f98d80c03a238671b4136e6530453d65262867d989bbe78244d0/aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b", size = 1706507, upload-time = "2026-03-31T21:58:21.094Z" }, - { url = "https://files.pythonhosted.org/packages/d4/56/ea11a9f01518bd5a2a2fcee869d248c4b8a0cfa0bb13401574fa31adf4d4/aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a", size = 1773465, upload-time = "2026-03-31T21:58:23.159Z" }, - { url = "https://files.pythonhosted.org/packages/eb/40/333ca27fb74b0383f17c90570c748f7582501507307350a79d9f9f3c6eb1/aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8", size = 1873523, upload-time = "2026-03-31T21:58:25.59Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" }, - { url = "https://files.pythonhosted.org/packages/fb/56/3f653d7f53c89669301ec9e42c95233e2a0c0a6dd051269e6e678db4fdb0/aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540", size = 1562351, upload-time = "2026-03-31T21:58:29.918Z" }, - { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" }, - { url = "https://files.pythonhosted.org/packages/98/fc/bfb437a99a2fcebd6b6eaec609571954de2ed424f01c352f4b5504371dd3/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46", size = 1730618, upload-time = "2026-03-31T21:58:34.728Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b6/c8534862126191a034f68153194c389addc285a0f1347d85096d349bbc15/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8", size = 1745185, upload-time = "2026-03-31T21:58:36.909Z" }, - { url = "https://files.pythonhosted.org/packages/0b/93/4ca8ee2ef5236e2707e0fd5fecb10ce214aee1ff4ab307af9c558bda3b37/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d", size = 1557311, upload-time = "2026-03-31T21:58:39.38Z" }, - { url = "https://files.pythonhosted.org/packages/57/ae/76177b15f18c5f5d094f19901d284025db28eccc5ae374d1d254181d33f4/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6", size = 1773147, upload-time = "2026-03-31T21:58:41.476Z" }, - { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" }, - { url = "https://files.pythonhosted.org/packages/e4/85/fc8601f59dfa8c9523808281f2da571f8b4699685f9809a228adcc90838d/aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc", size = 432637, upload-time = "2026-03-31T21:58:46.167Z" }, - { url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" }, - { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" }, - { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" }, - { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" }, - { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" }, - { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" }, - { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" }, - { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" }, - { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" }, - { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" }, - { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" }, - { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" }, - { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" }, - { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" }, - { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" }, - { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" }, - { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" }, - { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" }, - { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" }, - { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" }, - { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" }, - { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" }, - { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" }, - { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" }, - { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" }, - { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" }, - { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" }, - { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" }, - { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" }, + { url = "https://files.pythonhosted.org/packages/bc/97/bd137012dd97e1649162b099135a80e1fd59aaa807b2430fc448d1029aff/aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178", size = 506882, upload-time = "2026-06-07T21:07:15.501Z" }, + { url = "https://files.pythonhosted.org/packages/ef/79/e5cc690e9d922a66887ceeaca53a8ffd5a7b0be3816142b7abc433742d89/aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf", size = 515270, upload-time = "2026-06-07T21:07:17.53Z" }, + { url = "https://files.pythonhosted.org/packages/fe/22/a73ccbf9dbd6e26dda0b24d5fd5db7da92ee3383a79f47677ffb834c5c5b/aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd", size = 485841, upload-time = "2026-06-07T21:07:19.555Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b9/57ed8eaf596321c2ad747bd480fb1700dbd7177c60dfc9e4c187f629662e/aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe", size = 492088, upload-time = "2026-06-07T21:07:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/78/c0/5ebe5270a7c140d7c6f79dcb018640225f14d406c149e4eec04a7d82fe71/aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4", size = 501564, upload-time = "2026-06-07T21:07:23.388Z" }, + { url = "https://files.pythonhosted.org/packages/75/7f/8cdaa24fc7983865e0915153b96a9ac5bcdd3548d64c5a27d17cecccad2d/aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876", size = 751998, upload-time = "2026-06-07T21:07:25.046Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f4/c4227aacfacc5cb0cc2d119b65301d177912a6842cd64e120c47af76064f/aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da", size = 510918, upload-time = "2026-06-07T21:07:27.28Z" }, + { url = "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6", size = 508657, upload-time = "2026-06-07T21:07:29.252Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ed/3c0fb5c500fdd8e7ebc10d1889c04384fffa1a9163eac1356088ca9da1b1/aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96", size = 1757907, upload-time = "2026-06-07T21:07:31.03Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ab/d4c924d9bd5be3050c226612413ce68cb54c70d2c31b661bfc8d9a5b6a70/aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f", size = 1737565, upload-time = "2026-06-07T21:07:33.031Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/37326821ff779084020cdc33224d20b19f42f4183a500ff92022a739eda7/aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296", size = 1799018, upload-time = "2026-06-07T21:07:35.003Z" }, + { url = "https://files.pythonhosted.org/packages/b3/4f/6e947ba73e4ce09070761c05ed3a8ceb7c21f5e46798671d8b2aac0e4626/aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa", size = 1894416, upload-time = "2026-06-07T21:07:36.956Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6e/dbf1d0625dc711fb2851f4f3c3055c39ed58bae92082d8c627dbe6013736/aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451", size = 1783881, upload-time = "2026-06-07T21:07:39.063Z" }, + { url = "https://files.pythonhosted.org/packages/44/c2/5e25098a67268ed369483ae7d1a58bd0a13d03aab860d2a0e4a6eb25b046/aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c", size = 1587572, upload-time = "2026-06-07T21:07:41.058Z" }, + { url = "https://files.pythonhosted.org/packages/2a/bd/cf9cee17e140f942a3de73e658a543aa8fbf35a5fc67a9d2538d52d77f0b/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca", size = 1722137, upload-time = "2026-06-07T21:07:43.014Z" }, + { url = "https://files.pythonhosted.org/packages/89/6d/5684f8c59045c96f81a18cefbc1fbbd79d25b88f1c622f2a5c5c08fcb632/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09", size = 1755953, upload-time = "2026-06-07T21:07:45.933Z" }, + { url = "https://files.pythonhosted.org/packages/a8/40/35caf3170f8359760740a7d9aa0fff2e344bef98e1d1186f5a0f6dec17e6/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397", size = 1766479, upload-time = "2026-06-07T21:07:48.047Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a1/b0c61e7a137f0d81de49a82023a6df73c3c16d6fefb0f8e4a93d21639002/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080", size = 1580077, upload-time = "2026-06-07T21:07:50.069Z" }, + { url = "https://files.pythonhosted.org/packages/0b/41/194ea4623693009fcefebef7aef63c141754f153e9cd0d39d3b9e36c175c/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345", size = 1791688, upload-time = "2026-06-07T21:07:52.106Z" }, + { url = "https://files.pythonhosted.org/packages/ba/45/4de841f005cfe1fd63e2a2fe011262c515e2a62aa6994b15947e7d717ac9/aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588", size = 1761094, upload-time = "2026-06-07T21:07:54.113Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ae/dbce10533d3896d544d5053939ed75b7dc31a1b0973d959b1b5ae21028d6/aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780", size = 452662, upload-time = "2026-06-07T21:07:56.06Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/0bf1a19362c32f06229da5e7ddfcec91f93474d6307f7a2d3135e9c674dc/aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a", size = 479748, upload-time = "2026-06-07T21:07:58.319Z" }, + { url = "https://files.pythonhosted.org/packages/22/0a/62e7232dc9484fbec112ceb32efb6a624cc7994ec6e2b019286f17c4e8f2/aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8", size = 447723, upload-time = "2026-06-07T21:08:00.154Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a1/5fafa04e1ca91ddb47608699d60649c1c6db3cf41c99e78fc4056f9513db/aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15", size = 508531, upload-time = "2026-06-07T21:08:02.093Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/bfa02f699d87ffc86d5959270b28f1cb410add3ccaced8ed2e0b8a5238fc/aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8", size = 514718, upload-time = "2026-06-07T21:08:04.476Z" }, + { url = "https://files.pythonhosted.org/packages/85/a5/9594ad6289eebbc97d167c44213d557807f90e59115caad24de21ad2c3b1/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3", size = 487918, upload-time = "2026-06-07T21:08:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/b4/61/16a32c36c3c49edec122a3dc811f2057df2f94d3b14aa107c8017d981618/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba", size = 494014, upload-time = "2026-06-07T21:08:08.263Z" }, + { url = "https://files.pythonhosted.org/packages/9b/89/3ebcf96ed99c05bec9c434aaac6963fd3cbab4a786ae739908a144d9ce44/aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397", size = 502398, upload-time = "2026-06-07T21:08:10.244Z" }, + { url = "https://files.pythonhosted.org/packages/fd/3d/b74870a0c2d40c355928cd5b96c7a11fa821b8a40fc41365e64479b151fb/aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448", size = 758018, upload-time = "2026-06-07T21:08:12.447Z" }, + { url = "https://files.pythonhosted.org/packages/d3/66/f42f5c984d99e49c6cff5f26f590750f2e2f7ef1fcfb99966ab5be1b632e/aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004", size = 512462, upload-time = "2026-06-07T21:08:14.624Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a7/248e1aebe0c7810b0271e021a0f2a5eb6e78a051885b3c9df49f42a5802d/aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983", size = 512824, upload-time = "2026-06-07T21:08:16.572Z" }, + { url = "https://files.pythonhosted.org/packages/26/97/2aa0e5ba0727dc3bd5aaebb7ccbc510f7dfb7fb961ec87497cd496635ab1/aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe", size = 1749898, upload-time = "2026-06-07T21:08:18.635Z" }, + { url = "https://files.pythonhosted.org/packages/00/8d/e97f6c96c891d457c8479d92a514ba194d0412f981d72c70341ee18488ed/aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333", size = 1710114, upload-time = "2026-06-07T21:08:20.892Z" }, + { url = "https://files.pythonhosted.org/packages/6f/e6/aa8d7e863048c8fceb5cd6ce74017311cec3ead07847387e12265fb4444e/aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0", size = 1802541, upload-time = "2026-06-07T21:08:23.044Z" }, + { url = "https://files.pythonhosted.org/packages/83/a8/72193137de57fda4ebfae4563182d082c8856e3b6e9871d0b46f028fb369/aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a", size = 1875776, upload-time = "2026-06-07T21:08:25.288Z" }, + { url = "https://files.pythonhosted.org/packages/a0/18/938441025db6769a3464596b2410af3afde0b21eb2f204c6f766f68af4bd/aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602", size = 1760329, upload-time = "2026-06-07T21:08:27.363Z" }, + { url = "https://files.pythonhosted.org/packages/60/29/bf2496b4065e76e09fe48015aaffe5ce161d8f089b06ac6982070f653076/aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca", size = 1587293, upload-time = "2026-06-07T21:08:29.805Z" }, + { url = "https://files.pythonhosted.org/packages/49/a2/2136674d52123b1354bd05dd5753c318db47dc0c927cc70b27bab3755456/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35", size = 1714756, upload-time = "2026-06-07T21:08:32.094Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b9/e5fd2e6f915503081c0f9b1e8540947037929c70c191da2e4d54b31a21a1/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844", size = 1721052, upload-time = "2026-06-07T21:08:34.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/5a/2833e324a2263e104e31e2e91bc5bbee81bc499afd32203faee048a883f0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496", size = 1766888, upload-time = "2026-06-07T21:08:36.95Z" }, + { url = "https://files.pythonhosted.org/packages/57/fa/dea6511870913162f3b2e8c42a7614eb203a4540b8c2da43e0bfb0548f3c/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5", size = 1581679, upload-time = "2026-06-07T21:08:39.292Z" }, + { url = "https://files.pythonhosted.org/packages/14/bd/3cf0d55e71784b33534e9710a67d382d900598b4787fbce6cc7317f8c42a/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95", size = 1782021, upload-time = "2026-06-07T21:08:41.407Z" }, + { url = "https://files.pythonhosted.org/packages/c1/af/14bb5843eccbe234f4dfb78ab73e549d99727247e62ae5d62cbd22eaf5b0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444", size = 1742574, upload-time = "2026-06-07T21:08:43.795Z" }, + { url = "https://files.pythonhosted.org/packages/f2/1e/fbeb7af9210a67ac0f9c9bec0f8f4568497924e33137a3d5b48e1cf85f3f/aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0", size = 457773, upload-time = "2026-06-07T21:08:46.168Z" }, + { url = "https://files.pythonhosted.org/packages/f0/2b/13e8d741a9ec5db7d900c060554cf8352ab85e44e2a4469ebb9d377bda17/aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719", size = 485001, upload-time = "2026-06-07T21:08:48.401Z" }, + { url = "https://files.pythonhosted.org/packages/df/30/491acfa2c4d6c3ff59c49a14fc1b50be3241e25bbb0c84c09e2da4d11395/aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec", size = 453809, upload-time = "2026-06-07T21:08:50.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/e3/19dbe1a1f4cc6230eb9e314de7fe68053b0992f9302b27d12141a0b5db53/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2", size = 793320, upload-time = "2026-06-07T21:08:52.775Z" }, + { url = "https://files.pythonhosted.org/packages/7f/20/1b7182219ba1b108430d6e4dc53d25ae02dcfcf5a045b33af4e8c5167527/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340", size = 529077, upload-time = "2026-06-07T21:08:55Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d", size = 532476, upload-time = "2026-06-07T21:08:57.176Z" }, + { url = "https://files.pythonhosted.org/packages/7e/02/9ac85e081e53da2e061b02fa7758fe0a12d17b8ce2d1f5e6c7cb76730328/aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94", size = 1922347, upload-time = "2026-06-07T21:08:59.563Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3e/d3ba07a0ab38b5389e10bec4362d21e10a4f667cba2d79ba30837b3a5059/aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc", size = 1786465, upload-time = "2026-06-07T21:09:01.909Z" }, + { url = "https://files.pythonhosted.org/packages/0b/cb/e2ee978a00cfb2df829704a69528b18154eba5939f45bc1efa8f33aee4c5/aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251", size = 1909423, upload-time = "2026-06-07T21:09:04.357Z" }, + { url = "https://files.pythonhosted.org/packages/73/5d/1430334858b1022b58ae50399a918f0bd6fe8fa7fa183598d657ff61e040/aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1", size = 2001906, upload-time = "2026-06-07T21:09:06.722Z" }, + { url = "https://files.pythonhosted.org/packages/66/4e/560c7472d3d198a23aa5c8b19a5115bf6a9b77b7d3e4bb363da320430ad2/aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3", size = 1877095, upload-time = "2026-06-07T21:09:09.011Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f1/4745806578d447db4a784a8591e2dae3afdfc2bcb96f8f81271b13df6543/aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c", size = 1676222, upload-time = "2026-06-07T21:09:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c9/48255813cca749a229ef0ab476004ec623728ad79a9c0840616f6c076325/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203", size = 1842922, upload-time = "2026-06-07T21:09:14.118Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c0/bbd054e2bee909f529523a5af3891052606af5143c09f5f183ec3b234676/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1", size = 1825035, upload-time = "2026-06-07T21:09:16.447Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ae/90395d4376deceb74e09ec26b6adf7d2015a6f8802d6d84446af860fef04/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665", size = 1849512, upload-time = "2026-06-07T21:09:18.742Z" }, + { url = "https://files.pythonhosted.org/packages/93/bd/fb25f3049957553d4ce0ba6ae480aa2f592a6985497fca590837d16c1be0/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1", size = 1668571, upload-time = "2026-06-07T21:09:21.458Z" }, + { url = "https://files.pythonhosted.org/packages/3f/22/7f73303d64dd567ff3addca90b556690ed1233a47b8f55d242fb90af3681/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d", size = 1881159, upload-time = "2026-06-07T21:09:23.813Z" }, + { url = "https://files.pythonhosted.org/packages/44/be/0474c5a8b5640e1e4aa1923430a91f4151be82e511373fe764189b89aef5/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c", size = 1841409, upload-time = "2026-06-07T21:09:26.207Z" }, + { url = "https://files.pythonhosted.org/packages/7b/3c/bb4a7cba26956cb3da4553cc2056cf67be5b5ff6e6d8fa4fbdff73bfb7ae/aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365", size = 494166, upload-time = "2026-06-07T21:09:28.505Z" }, + { url = "https://files.pythonhosted.org/packages/8a/84/ec80c2c1f66a952555a9f86df6b33af65108a6febfa0471b69013a12f807/aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9", size = 530255, upload-time = "2026-06-07T21:09:30.843Z" }, + { url = "https://files.pythonhosted.org/packages/2a/71/6e22be134a4061ada85a92951b842f2657f17d926b727f3f94c56ae963d6/aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6", size = 469640, upload-time = "2026-06-07T21:09:33.028Z" }, ] [[package]] @@ -135,6 +152,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, ] +[[package]] +name = "ast-serialize" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/9d/09e27731bd5864a9ce04e3244074e674bb8936bf62b45e0357248717adac/ast_serialize-0.5.0.tar.gz", hash = "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6", size = 61157, upload-time = "2026-05-17T17:48:29.429Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/9a/13dde51ba9e15f8b97957ab7cb0120d0e381524d651c6bd630b9c359227f/ast_serialize-0.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a", size = 1183520, upload-time = "2026-05-17T17:47:30.831Z" }, + { url = "https://files.pythonhosted.org/packages/37/de/5a7f0a9fe68944f536632a5af84676739c7d2582be42deb082634bf3a754/ast_serialize-0.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b", size = 1175779, upload-time = "2026-05-17T17:47:32.551Z" }, + { url = "https://files.pythonhosted.org/packages/9c/81/0bb853e76e4f6e9a1855d569003c59e19ffac45f7079d91505d1bb212f92/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1", size = 1233750, upload-time = "2026-05-17T17:47:34.731Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/4cf705beeccc08754d0bbda99aefff26110e209b9a07ac8a6b60eec48531/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6", size = 1235942, upload-time = "2026-05-17T17:47:36.287Z" }, + { url = "https://files.pythonhosted.org/packages/26/c8/ee097e437ea27dd2b8b227865c875492b585650a5802a22d82b304c8201b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2", size = 1442517, upload-time = "2026-05-17T17:47:38.17Z" }, + { url = "https://files.pythonhosted.org/packages/ff/bd/68063442838f1ba68ec72b5436430bc75b3bb17a1a3c3063f09b0c05ae2b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903", size = 1254081, upload-time = "2026-05-17T17:47:39.826Z" }, + { url = "https://files.pythonhosted.org/packages/50/e2/1e520793bc6a4e4524a6ab022391e827825eaa0c3811828bfdc6852eca26/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261", size = 1259910, upload-time = "2026-05-17T17:47:41.369Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e1/49b60f467979979cfe6913b43948ff25bca971ad0591d181812f163a988e/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027", size = 1250678, upload-time = "2026-05-17T17:47:43.702Z" }, + { url = "https://files.pythonhosted.org/packages/74/ba/66ab9555de6275677566f6574e5ef6c29cb185ea866f643bc06f8280a8ee/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937", size = 1301603, upload-time = "2026-05-17T17:47:46.256Z" }, + { url = "https://files.pythonhosted.org/packages/66/42/6aca9b9abc710014b2be9059689e5dd1679339e78f567ffb4d255a9e2050/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c", size = 1410332, upload-time = "2026-05-17T17:47:47.899Z" }, + { url = "https://files.pythonhosted.org/packages/47/68/2f76594432a22581ecf878b5e75a9b8601c24b2241cf0bbeb1e21fcf370c/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b", size = 1509979, upload-time = "2026-05-17T17:47:50.942Z" }, + { url = "https://files.pythonhosted.org/packages/40/ac/a93c9b58292653f6c595752f677a08e608f903b710594909e9231a389b3b/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab", size = 1505002, upload-time = "2026-05-17T17:47:54.093Z" }, + { url = "https://files.pythonhosted.org/packages/14/2e/b278f68c497ee2f1d1576cbbef8db5281cd4a5f2db040537592ac9c8862e/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3", size = 1456231, upload-time = "2026-05-17T17:47:56.311Z" }, + { url = "https://files.pythonhosted.org/packages/0b/43/419be1c566a4c504cd8fd60ce2f84e790f295495c0f327cfaeadf3d51012/ast_serialize-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38", size = 1058668, upload-time = "2026-05-17T17:47:58.305Z" }, + { url = "https://files.pythonhosted.org/packages/03/6f/c9d4d549295ed05111aeb8853232d1afd9d0a179fddb01eeffbb3a4a6842/ast_serialize-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c", size = 1101075, upload-time = "2026-05-17T17:48:00.35Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/d00c5ab30c58222e07d62956fca86c59d91b9ad32997e633c38b526623a3/ast_serialize-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb", size = 1075347, upload-time = "2026-05-17T17:48:01.753Z" }, + { url = "https://files.pythonhosted.org/packages/e0/9e/dc2530acb3a60dc6e46d65abf27d1d9f86721694757906a148d90a6860de/ast_serialize-0.5.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101", size = 1191380, upload-time = "2026-05-17T17:48:03.738Z" }, + { url = "https://files.pythonhosted.org/packages/26/0a/bd3d18a582f273d6c843d16bb9e22e9e16365ff7991e92f18f798e9f1224/ast_serialize-0.5.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a", size = 1183879, upload-time = "2026-05-17T17:48:05.463Z" }, + { url = "https://files.pythonhosted.org/packages/40/ae/1f919100f8620887af58fcc381c61a1f218cdf89c6e155f87b213e61010a/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211", size = 1244529, upload-time = "2026-05-17T17:48:07.008Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ca/6376559dcce707cdbc1d0d9a13c8d3baaaa501e949ce0ebdc4230cd881aa/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf", size = 1240560, upload-time = "2026-05-17T17:48:08.46Z" }, + { url = "https://files.pythonhosted.org/packages/35/b2/a620e206b5aeb7efbf2710336df57d457cffbb3991076bbcc1147ef9abd4/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9", size = 1451172, upload-time = "2026-05-17T17:48:09.922Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e0/4ad5c04c24a40481b2935ce9a0ccdb6023dc8b667167d06ae530cc3512f2/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee", size = 1265072, upload-time = "2026-05-17T17:48:11.469Z" }, + { url = "https://files.pythonhosted.org/packages/b2/71/4d1d479aa56d0101c40e17720c3d6ac2af7269ea0487a80b18e7bfd1a5b7/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809", size = 1270488, upload-time = "2026-05-17T17:48:13.575Z" }, + { url = "https://files.pythonhosted.org/packages/6d/4f/0de1bbe06f6edef9fde4ed12ca8e7b3ec7e6e2bd4e672c5af487f7957665/ast_serialize-0.5.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43", size = 1260702, upload-time = "2026-05-17T17:48:15.141Z" }, + { url = "https://files.pythonhosted.org/packages/75/61/e00872439cfdddcc3c1b6cdaa6e5d904ba8e26a18807c67c4e14409d0ca8/ast_serialize-0.5.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934", size = 1311182, upload-time = "2026-05-17T17:48:16.779Z" }, + { url = "https://files.pythonhosted.org/packages/76/8e/699a5b955f7926956c95e9e1d74132acad73c2fe7a426f94da89123c20aa/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759", size = 1421410, upload-time = "2026-05-17T17:48:18.527Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ae/d5b7626874478997adc7a29ab28accf21e596fb590c944290401dfd0b29e/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887", size = 1516587, upload-time = "2026-05-17T17:48:20.133Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ce/b59e02a82d9c4244d64cde502e0b00e83e38816abe19155ceb5437402c7f/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27", size = 1515171, upload-time = "2026-05-17T17:48:21.921Z" }, + { url = "https://files.pythonhosted.org/packages/8b/38/d8d90042747d05aa08d4efcf1c99035a5f670a6bf4c214d31644392afbca/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d", size = 1464668, upload-time = "2026-05-17T17:48:23.544Z" }, + { url = "https://files.pythonhosted.org/packages/dd/51/5b840c4df7334104cecffa28f23904fe81ca89ca223d2450e288de39fd3c/ast_serialize-0.5.0-cp39-abi3-win32.whl", hash = "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a", size = 1068311, upload-time = "2026-05-17T17:48:25.027Z" }, + { url = "https://files.pythonhosted.org/packages/41/11/ca5672c7d491825bc4cd6702dea106a6b60d928707712ec257c7833ae476/ast_serialize-0.5.0-cp39-abi3-win_amd64.whl", hash = "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590", size = 1108931, upload-time = "2026-05-17T17:48:26.591Z" }, + { url = "https://files.pythonhosted.org/packages/45/19/cc8bd127d28a43da249aa955cfd164cf8fd534e79e42cea96c4854d72fd0/ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", size = 1081181, upload-time = "2026-05-17T17:48:28.122Z" }, +] + [[package]] name = "asyncpg" version = "0.30.0" @@ -207,7 +264,7 @@ wheels = [ [[package]] name = "black" -version = "24.10.0" +version = "26.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -215,14 +272,21 @@ dependencies = [ { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, + { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813, upload-time = "2024-10-07T19:20:50.361Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986, upload-time = "2024-10-07T19:28:50.684Z" }, - { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085, upload-time = "2024-10-07T19:28:12.093Z" }, - { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928, upload-time = "2024-10-07T19:24:15.233Z" }, - { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875, upload-time = "2024-10-07T19:24:42.762Z" }, - { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898, upload-time = "2024-10-07T19:20:48.317Z" }, + { url = "https://files.pythonhosted.org/packages/3f/5c/c384363980e11e25ca6b93205949bb331fbf35f4e0dbec376dfa6326cec8/black-26.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b36cf2ddf5566e205f6535f782a62194a184d33e175b64ae8c40b1737522be3", size = 2009020, upload-time = "2026-05-18T17:05:28.132Z" }, + { url = "https://files.pythonhosted.org/packages/0b/df/9f31c5e0babbfed77d505fc5d120beb98b21b33feaeded3924ea941fe360/black-26.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f7ea64ebfa01b50f693508fc39f875e264446d3b097088f84f203b9d09618a0", size = 1813335, upload-time = "2026-05-18T17:05:31.266Z" }, + { url = "https://files.pythonhosted.org/packages/fb/24/8e7b9a2fa61b0afd82209efe937557d180a1fa055bd7f6161eb9defc3719/black-26.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecb3e624844c798144e9bd986954e0adc81d8911a1f30f375e1252fe26e8c294", size = 1881614, upload-time = "2026-05-18T17:05:32.718Z" }, + { url = "https://files.pythonhosted.org/packages/49/ad/b4e0d9365ba8ac34f6bbab62a4b1b2dd5d618fac3fa1b8db968c844201b5/black-26.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:e1a26503279b6b310669fb0b219c39e4820b77e8189fe80f522bb511f247db0a", size = 1488925, upload-time = "2026-05-18T17:05:34.259Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4b/652b859bf5df88a751c30451b09338f7fd26a77d1271c666992f836b7711/black-26.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c34b25da232ead53a6f335b76dbea124f4d152ad568b9080d6f944bc2b34b52", size = 1289883, upload-time = "2026-05-18T17:05:36.019Z" }, + { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" }, + { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" }, + { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" }, + { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" }, ] [[package]] @@ -254,11 +318,11 @@ filecache = [ [[package]] name = "certifi" -version = "2026.2.25" +version = "2026.5.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, ] [[package]] @@ -374,14 +438,14 @@ wheels = [ [[package]] name = "click" -version = "8.3.2" +version = "8.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" }, + { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, ] [[package]] @@ -395,124 +459,124 @@ wheels = [ [[package]] name = "coverage" -version = "7.13.5" +version = "7.14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/fd/0ab2772530e946e1be1abd0bc09e647ec9b02e88f0867857601fefca8953/coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be", size = 920132, upload-time = "2026-05-26T20:41:36.783Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/8c/74fedc9663dcf168b0a059d4ea756ecae4da77a489048f94b5f512a8d0b3/coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1", size = 219576, upload-time = "2026-03-17T10:31:09.045Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3", size = 219942, upload-time = "2026-03-17T10:31:10.708Z" }, - { url = "https://files.pythonhosted.org/packages/5f/13/93419671cee82b780bab7ea96b67c8ef448f5f295f36bf5031154ec9a790/coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26", size = 250935, upload-time = "2026-03-17T10:31:12.392Z" }, - { url = "https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3", size = 253541, upload-time = "2026-03-17T10:31:14.247Z" }, - { url = "https://files.pythonhosted.org/packages/4e/5e/3ee3b835647be646dcf3c65a7c6c18f87c27326a858f72ab22c12730773d/coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b", size = 254780, upload-time = "2026-03-17T10:31:16.193Z" }, - { url = "https://files.pythonhosted.org/packages/44/b3/cb5bd1a04cfcc49ede6cd8409d80bee17661167686741e041abc7ee1b9a9/coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a", size = 256912, upload-time = "2026-03-17T10:31:17.89Z" }, - { url = "https://files.pythonhosted.org/packages/1b/66/c1dceb7b9714473800b075f5c8a84f4588f887a90eb8645282031676e242/coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969", size = 251165, upload-time = "2026-03-17T10:31:19.605Z" }, - { url = "https://files.pythonhosted.org/packages/b7/62/5502b73b97aa2e53ea22a39cf8649ff44827bef76d90bf638777daa27a9d/coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161", size = 252908, upload-time = "2026-03-17T10:31:21.312Z" }, - { url = "https://files.pythonhosted.org/packages/7d/37/7792c2d69854397ca77a55c4646e5897c467928b0e27f2d235d83b5d08c6/coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15", size = 250873, upload-time = "2026-03-17T10:31:23.565Z" }, - { url = "https://files.pythonhosted.org/packages/a3/23/bc866fb6163be52a8a9e5d708ba0d3b1283c12158cefca0a8bbb6e247a43/coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1", size = 255030, upload-time = "2026-03-17T10:31:25.58Z" }, - { url = "https://files.pythonhosted.org/packages/7d/8b/ef67e1c222ef49860701d346b8bbb70881bef283bd5f6cbba68a39a086c7/coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6", size = 250694, upload-time = "2026-03-17T10:31:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/46/0d/866d1f74f0acddbb906db212e096dee77a8e2158ca5e6bb44729f9d93298/coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17", size = 252469, upload-time = "2026-03-17T10:31:29.472Z" }, - { url = "https://files.pythonhosted.org/packages/7a/f5/be742fec31118f02ce42b21c6af187ad6a344fed546b56ca60caacc6a9a0/coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85", size = 222112, upload-time = "2026-03-17T10:31:31.526Z" }, - { url = "https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b", size = 222923, upload-time = "2026-03-17T10:31:33.633Z" }, - { url = "https://files.pythonhosted.org/packages/48/af/fea819c12a095781f6ccd504890aaddaf88b8fab263c4940e82c7b770124/coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664", size = 221540, upload-time = "2026-03-17T10:31:35.445Z" }, - { url = "https://files.pythonhosted.org/packages/23/d2/17879af479df7fbbd44bd528a31692a48f6b25055d16482fdf5cdb633805/coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d", size = 220262, upload-time = "2026-03-17T10:31:37.184Z" }, - { url = "https://files.pythonhosted.org/packages/5b/4c/d20e554f988c8f91d6a02c5118f9abbbf73a8768a3048cb4962230d5743f/coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0", size = 220617, upload-time = "2026-03-17T10:31:39.245Z" }, - { url = "https://files.pythonhosted.org/packages/29/9c/f9f5277b95184f764b24e7231e166dfdb5780a46d408a2ac665969416d61/coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806", size = 261912, upload-time = "2026-03-17T10:31:41.324Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f6/7f1ab39393eeb50cfe4747ae8ef0e4fc564b989225aa1152e13a180d74f8/coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3", size = 263987, upload-time = "2026-03-17T10:31:43.724Z" }, - { url = "https://files.pythonhosted.org/packages/a0/d7/62c084fb489ed9c6fbdf57e006752e7c516ea46fd690e5ed8b8617c7d52e/coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9", size = 266416, upload-time = "2026-03-17T10:31:45.769Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f6/df63d8660e1a0bff6125947afda112a0502736f470d62ca68b288ea762d8/coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd", size = 267558, upload-time = "2026-03-17T10:31:48.293Z" }, - { url = "https://files.pythonhosted.org/packages/5b/02/353ca81d36779bd108f6d384425f7139ac3c58c750dcfaafe5d0bee6436b/coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606", size = 261163, upload-time = "2026-03-17T10:31:50.125Z" }, - { url = "https://files.pythonhosted.org/packages/2c/16/2e79106d5749bcaf3aee6d309123548e3276517cd7851faa8da213bc61bf/coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e", size = 263981, upload-time = "2026-03-17T10:31:51.961Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/c29e0c59ffa6942030ae6f50b88ae49988e7e8da06de7ecdbf49c6d4feae/coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0", size = 261604, upload-time = "2026-03-17T10:31:53.872Z" }, - { url = "https://files.pythonhosted.org/packages/40/48/097cdc3db342f34006a308ab41c3a7c11c3f0d84750d340f45d88a782e00/coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87", size = 265321, upload-time = "2026-03-17T10:31:55.997Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1f/4994af354689e14fd03a75f8ec85a9a68d94e0188bbdab3fc1516b55e512/coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479", size = 260502, upload-time = "2026-03-17T10:31:58.308Z" }, - { url = "https://files.pythonhosted.org/packages/22/c6/9bb9ef55903e628033560885f5c31aa227e46878118b63ab15dc7ba87797/coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2", size = 262688, upload-time = "2026-03-17T10:32:00.141Z" }, - { url = "https://files.pythonhosted.org/packages/14/4f/f5df9007e50b15e53e01edea486814783a7f019893733d9e4d6caad75557/coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", size = 222788, upload-time = "2026-03-17T10:32:02.246Z" }, - { url = "https://files.pythonhosted.org/packages/e1/98/aa7fccaa97d0f3192bec013c4e6fd6d294a6ed44b640e6bb61f479e00ed5/coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", size = 223851, upload-time = "2026-03-17T10:32:04.416Z" }, - { url = "https://files.pythonhosted.org/packages/3d/8b/e5c469f7352651e5f013198e9e21f97510b23de957dd06a84071683b4b60/coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", size = 222104, upload-time = "2026-03-17T10:32:06.65Z" }, - { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, - { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, - { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, - { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, - { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, - { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, - { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, - { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, - { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, - { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, - { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, - { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, - { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, - { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, - { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, - { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, - { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, - { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, - { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, - { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/5f6d56327c62b185225d145191c607e07515294a0aa6338e58805cd4a5ac/coverage-7.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:be9f2c802dcfce3f71298303aa5dad0dce440a76c52f2f60dacd8656dab78793", size = 220044, upload-time = "2026-05-26T20:39:29.902Z" }, + { url = "https://files.pythonhosted.org/packages/75/92/e82aca356744cbbc0f77a0b623e38918c1872361963413a3bab5d0340393/coverage-7.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6223a72fd0e4c7156353ec0f08a5f93623e1d3034d0e2683b9bb8ea674131b1d", size = 220412, upload-time = "2026-05-26T20:39:31.561Z" }, + { url = "https://files.pythonhosted.org/packages/27/c9/385bde0bf7ed0f4bf3a7ee5367060a86b5d218718cfd6fb943c0f836b34f/coverage-7.14.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7279d2110a28cebc738b6459ecda2771735a4c18465fbbd36b3288fe5ed92247", size = 251412, upload-time = "2026-05-26T20:39:33.337Z" }, + { url = "https://files.pythonhosted.org/packages/51/8c/23faf6a2343a0d17f960a4bd56c43bc7eb4cf312f774dd6ceebd82c7d8fc/coverage-7.14.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9eeb3fcbc13ba40dfbdb22d01d196a28e9cef9ed4c29b60061a1e0e823a9929d", size = 254008, upload-time = "2026-05-26T20:39:35.009Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/36f4aa9ca8a815e6036156e80706a67828bb97bd826948244f6996dda957/coverage-7.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f0cfc27c539f07cf5c0a4cfe211d0b6cae039f8f40526dbaa71944e64b50a7b", size = 255241, upload-time = "2026-05-26T20:39:36.71Z" }, + { url = "https://files.pythonhosted.org/packages/ca/79/95266316352f90f6b1c6736bb413302edfde2453fb32422d3911642691b3/coverage-7.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:221c70f316241a78e77e607c227cefc8808d4e08f28d99c04f35694690e940be", size = 257373, upload-time = "2026-05-26T20:39:38.412Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9c/58316d1f66c488b5fca8a0eb3e98348807813efa8a0d0833b9021be27488/coverage-7.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da028256b04ec30e5e0114b6f76172938c313991f0a2d3d894271315cf5d5e43", size = 251635, upload-time = "2026-05-26T20:39:40.268Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5a/ca2398a568e16fed7bb713e84ba3603a7164fb65779abe645c565ec890d5/coverage-7.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a085d7005236a767e3426148b2c407e53ad61695c562f8a81da2d373324901", size = 253373, upload-time = "2026-05-26T20:39:42.145Z" }, + { url = "https://files.pythonhosted.org/packages/6e/2c/0396562c32deaebe7be51d865b3a41e9a87d7561acafe1a28f53b07e019a/coverage-7.14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b553d04b5e778a8e56d57eb134aff42a92718ecba45e79c4764ecfa40efd92ff", size = 251341, upload-time = "2026-05-26T20:39:43.907Z" }, + { url = "https://files.pythonhosted.org/packages/fd/8f/a94f9221184c9cae1ee115820e3798e48b6b17777a9f19e46fb9a0c8dc74/coverage-7.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:46f714d2fb8ae2f4f29f23ada7f1e79b759fff5a70f94a1dac23af204c3ec9e4", size = 255497, upload-time = "2026-05-26T20:39:46.166Z" }, + { url = "https://files.pythonhosted.org/packages/71/69/505d70e47db1eaebcd002c39759707621ef184cd6b1ae084d9f41293f323/coverage-7.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1896f5e19ff3f0431c7ce2172adc54890fd97f86b59ced8ca1649145d9ffe35d", size = 251159, upload-time = "2026-05-26T20:39:48.03Z" }, + { url = "https://files.pythonhosted.org/packages/e0/aa/58681c383aa33a9d2ed40a02d7a22fbf780d1fa4d575396365777828198c/coverage-7.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62fd185ef9df3c33d1c8178c5af105f762afbad96038de9a4ae100aa6297ca33", size = 252934, upload-time = "2026-05-26T20:39:49.872Z" }, + { url = "https://files.pythonhosted.org/packages/eb/fd/11c928cd6bdffc7074bb5965c173d9ebf517fb00205e1da524b98d29ef92/coverage-7.14.1-cp313-cp313-win32.whl", hash = "sha256:ab4af6352741a604c431c6072fce5bee33bf0f20dc7a56618d6bf6bb89e9810c", size = 222584, upload-time = "2026-05-26T20:39:51.68Z" }, + { url = "https://files.pythonhosted.org/packages/6f/92/fb416fc26d340dcba19518c418d6048e913186e17243982c5e435e41fa7a/coverage-7.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af486dabe8954d03b087f0021540897afe084f04e16ff5579e08cc46f871416", size = 223394, upload-time = "2026-05-26T20:39:53.472Z" }, + { url = "https://files.pythonhosted.org/packages/73/c6/02d56e3867972f77d5036de924643f26c056e848f00452cafb4dbc3c29b4/coverage-7.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:2224f89ffd0c5605ccce1ed7a584da162bc7c55f601ab1c946bc9de31a486b42", size = 222015, upload-time = "2026-05-26T20:39:55.374Z" }, + { url = "https://files.pythonhosted.org/packages/4d/9e/fcc77914050df73f7662fa1f00902774c79c075a8388ab334074574bf77e/coverage-7.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de286598cc65d2b489411174b1faec2f5a7775fb3201fd925db2a76b4030f37d", size = 220733, upload-time = "2026-05-26T20:39:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/f7/67/2963cbdaf5cbadec44efa3a1e39eaa1f02df4079585f05387607a221e126/coverage-7.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:042c46ded7c288aeb07cf14a28b6c1e10b78fcba40171c3fa1e939377eeef0b5", size = 221086, upload-time = "2026-05-26T20:39:59.019Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c5/8701645574e11881f2f47d8930f98bc48b5d43b25eb5b4430dfc4a2f9f48/coverage-7.14.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f4ddbe407477f04c45115d1a4e5bc480f753553b534d338d4c3358b1cdd0ea52", size = 262381, upload-time = "2026-05-26T20:40:00.822Z" }, + { url = "https://files.pythonhosted.org/packages/7c/28/7a64d73598263e0c5abd5084211a8474488d31b3c552ff531c719dfcff62/coverage-7.14.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d13e6725992e2d2fd7d81d4f5241952d13740121dfd501da09201be39b2c003a", size = 264458, upload-time = "2026-05-26T20:40:02.506Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d8/4969179db9f7eb4df218e69540adf829d1c835f59452513d065d15446802/coverage-7.14.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f747dc8edcfe740130f28f32f3995e955494285717e86ee25af51db2219df08a", size = 266884, upload-time = "2026-05-26T20:40:04.421Z" }, + { url = "https://files.pythonhosted.org/packages/a6/78/a45d5794dbc9bafd97afc96a4377c86c7820d78b6cf51b89bc1d4e919275/coverage-7.14.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced2f09ef276fd58611a1ef502164ad266d2b75174e5a40cabbdb4033f9f6cf2", size = 268022, upload-time = "2026-05-26T20:40:06.298Z" }, + { url = "https://files.pythonhosted.org/packages/21/cb/4f5e354e9e3e67af96bd4e57113e6db6b22298c7168b13eec408a549903d/coverage-7.14.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b84800013769a78ccb9ef4659402e26d06867e337b61ec365f77ad008adea80e", size = 261631, upload-time = "2026-05-26T20:40:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ec/49/eced49af4cb996d5d8b7e94e736175c513e4facd3398507b89892b4326d8/coverage-7.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ea8cd6ca0ee9f616aaef3afc6882e32c2cbf18b00d96313ffd76af650574034d", size = 264443, upload-time = "2026-05-26T20:40:10.137Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/5603a88a7c5913a6b54f6cb1a8c46f7b39cbb30f27cd3f492908da09b2d7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:aa5e304a873fabddc11e484e9b6b738bd38bd7bed17b09aa84eecf5332e8b8bb", size = 262069, upload-time = "2026-05-26T20:40:11.999Z" }, + { url = "https://files.pythonhosted.org/packages/f0/59/2ae3cb79da554a06c8619d6c88ea19dd1e4aed4b834b6a83bb1fa243bdc5/coverage-7.14.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5a1c5215be81035e629d5bc756650634d0bf31991038db7a0eccb90f025ce16d", size = 265780, upload-time = "2026-05-26T20:40:13.858Z" }, + { url = "https://files.pythonhosted.org/packages/af/5f/b130c1dc999031f2648bd25317fbce505ad8d5562079b4ed81e736a84967/coverage-7.14.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:79058c47dae6788504b5effb319961bcd72d7240551464b91d474bc0ed186d69", size = 260970, upload-time = "2026-05-26T20:40:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/87/d1/ec13ccddeb48ec963bdfa72a11224bac2584bd045ba13beca82f8113e9c7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:370c5afae3fa0658e11694a32b24c2778f6bc2d17718121f94ee185e69f26b54", size = 263157, upload-time = "2026-05-26T20:40:18.382Z" }, + { url = "https://files.pythonhosted.org/packages/cf/c2/cd91ead503045161092d3845f7bb95ea2f25131ce96d3e314dd835d91b9c/coverage-7.14.1-cp313-cp313t-win32.whl", hash = "sha256:3758dd0a7f1fa57365ef2e781df0f0731d38b6e3772259d13dae4bd8a958d4b1", size = 223259, upload-time = "2026-05-26T20:40:20.381Z" }, + { url = "https://files.pythonhosted.org/packages/71/9f/1e28d97e6bd2c76b07f38b7c02870f1371255ff6717f54eca578fcbbdd0e/coverage-7.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:6ff665fb023a77386fe11685190cee1f60a7d635994a30d9b0a061533d470fce", size = 224320, upload-time = "2026-05-26T20:40:22.316Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e0/d936e908f0e1efa55e52b91e01b52f1055cef5e1ab2718493390ed8e2fb8/coverage-7.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:17a5a241e5997621a956a7f402a7433ef4221e5152809b785bec79e2323799f1", size = 222577, upload-time = "2026-05-26T20:40:24.894Z" }, + { url = "https://files.pythonhosted.org/packages/d6/34/fc2f101b151af3799a101f0550b0454aa008afdc0add677394ec4aa8ea10/coverage-7.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d5ed429d0b8edaac649e889b4ffcedb6c80b06629a3f93050e3dddfb99235bee", size = 220091, upload-time = "2026-05-26T20:40:27.249Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a7/1ebae2ab5b961b5c79bb09fe7b3ac99edb190d8be4a8c510b2cf66f46468/coverage-7.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8011224a62280e50dab346960c03cf47aca1a1e09e608c0fb33fd6e0cc8e9500", size = 220421, upload-time = "2026-05-26T20:40:30.084Z" }, + { url = "https://files.pythonhosted.org/packages/5e/90/92aca9cf0acc95123c96cd1eb1f08917897a7f5dee01e15738922971ec31/coverage-7.14.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:12c42ec1e14f553c4f817e989365982e646e27211f10a0f717855b94a79c8906", size = 251466, upload-time = "2026-05-26T20:40:32.542Z" }, + { url = "https://files.pythonhosted.org/packages/26/2b/78048cbe3b999f6cbf9cc0d90abba6a88a3e0863a8c1c6cbc762f3f8802f/coverage-7.14.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06144cd511cf2624873a035c5069cf297144f6e77a73ee3d7a55b605ec5efb42", size = 253973, upload-time = "2026-05-26T20:40:34.473Z" }, + { url = "https://files.pythonhosted.org/packages/8e/21/c2e33b29d1cfde484a19d437afc343c6cd30b08d78cbbf9f5aff14e57b2b/coverage-7.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a311d8e1da24be5c1ccf85cbfb06315dbaa1703d5a1eab3f6432c72b837917c8", size = 255318, upload-time = "2026-05-26T20:40:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ee/aad2f108d63b769121005302f16bf66db8625c88ceaba466942e09a2607e/coverage-7.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c79cead5b5bc584d9c71451cb984d0e3a84e0c0937379c8efcbf27c8d661b851", size = 257633, upload-time = "2026-05-26T20:40:40.164Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f8/11a2c29b4fd76d9849f81d0bb812ec0017a9396df3217214e38934a8c837/coverage-7.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dcbf65f1f66a26cdd88c35cf68fb4729c5d1cd2e88added72420541dfb212034", size = 251488, upload-time = "2026-05-26T20:40:42.631Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b8/9a5820de4b8ac2b71d85e3b5fb49108d7469c665f0e2ad0dd7569023e305/coverage-7.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fd86572566fb40189a8260446158235159bc7a82dfbc87a3b39cf4fb57fcec1c", size = 253329, upload-time = "2026-05-26T20:40:45.208Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ff/f33e4823667e27548e8fd8df44217515303f9808d0ff29817db56f87d990/coverage-7.14.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7771b601718fdde84832c3a434ca9bbf4ae9adbc49d84198b4110700c3c77c36", size = 251291, upload-time = "2026-05-26T20:40:47.502Z" }, + { url = "https://files.pythonhosted.org/packages/68/9b/489db0ebb209054766b90a9014a45f6d26eb724c02ec21311c3733b5a644/coverage-7.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:39b21e212c55af06fa375e3dbf90a8a8e38792f3a910c580066d23563830ddd5", size = 255564, upload-time = "2026-05-26T20:40:49.372Z" }, + { url = "https://files.pythonhosted.org/packages/27/b5/16bc2d4c2409b23c7737edb68c83bc89e345f378050549fe1d75ac7d34d5/coverage-7.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f2302660e32562a532b442480121aef8aa61a5bdb20b30bf0adab29f10a5a4b4", size = 251107, upload-time = "2026-05-26T20:40:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/7d/0c/2629997469a00cd069d588a41c9dc887610f2775ae89d250c4791e65272a/coverage-7.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03a6f93c1ec3b7f2e77b5dbcc5573a2c21f12529a5c6bbe0f16f72303cc2fa4d", size = 252764, upload-time = "2026-05-26T20:40:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ee/f78d63c8f079e0d7211c7e2401fa17e311514534ba61bae03e4b287ce4ab/coverage-7.14.1-cp314-cp314-win32.whl", hash = "sha256:8a3ce026d73290f42f08dafecbd82c193a74df280461fbf97300fec51fd133ee", size = 222837, upload-time = "2026-05-26T20:40:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b9/be539854f93a70dfbeec69117f33ec70dc42ff0b65b5b07ab8d40d04228e/coverage-7.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:114c95ef29302423b87d159075805f4ab973254a2638a5d7d046c94887cc87d7", size = 223650, upload-time = "2026-05-26T20:40:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9e/24e2842fef40f35ac82ba3a7719c8023d011bf3bf652d0675316a9d088a1/coverage-7.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:a07891c3f4805442b31b71e84ba3cf29ed1aa9a428284e06deeb4b23e5b46343", size = 222218, upload-time = "2026-05-26T20:41:00.321Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/ac0a9df5fe31c1e8bdd658074905fc12844a05c1a7e3fdb8417e97c31e23/coverage-7.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1101a5ebb083aecb625ebb6209d4105b58f647b093cb2dc8122d7b33f743cfe1", size = 220822, upload-time = "2026-05-26T20:41:02.281Z" }, + { url = "https://files.pythonhosted.org/packages/32/cf/f964fd9aff20323f9f1a726c97135f8a76bcd87b92dad141a456a43f3c64/coverage-7.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:851b9e1e4e8a4608e77c79714b2e77c0970d2ed7202a05e92ae407817481887b", size = 221084, upload-time = "2026-05-26T20:41:04.593Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5e/7e5ef2aba844de2b80d678619fcf0841b42e3f37f16411226f3fe4c1016f/coverage-7.14.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d5b89cdfb2ee051b71e8c3c70bd81a9eff81100f736a269136fe1a68efe00474", size = 262454, upload-time = "2026-05-26T20:41:06.641Z" }, + { url = "https://files.pythonhosted.org/packages/64/62/75809bded87015cc4935524218a2a8ed8dd1a8498bfed30a2f4f7a4b4d34/coverage-7.14.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86", size = 264578, upload-time = "2026-05-26T20:41:08.556Z" }, + { url = "https://files.pythonhosted.org/packages/f3/42/d33392dc14633525012d2d504fa1a33b05538bf535f5c1d64675e5754b78/coverage-7.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d69af5dea2de76fc485a83032a630523f985198b7e25be901ec60181587b01e", size = 266981, upload-time = "2026-05-26T20:41:10.824Z" }, + { url = "https://files.pythonhosted.org/packages/2a/49/0157c4428c2aca7f1e09d5565930586fd5ae36f1655f08b0daa7cf1fcae1/coverage-7.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35ab22d91de736e8966b980dc355cbcdd2c6dbbcfe275f9a2991bc8a91b3df65", size = 268112, upload-time = "2026-05-26T20:41:12.966Z" }, + { url = "https://files.pythonhosted.org/packages/96/26/86b9ce71f4092b1ed325ce1421698081df1286b833400b6836912834d6e0/coverage-7.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:357d4e32935c36588aaba057d734fa32428c360c9fc2e4442afbf1b646beee6e", size = 261558, upload-time = "2026-05-26T20:41:15Z" }, + { url = "https://files.pythonhosted.org/packages/20/4c/c311210c5472cf5401d8422b0d7812cdd520f24417673afabda6c323faca/coverage-7.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:51bd64741cc6fa065abd300ede1afe5a5291ece9c31da8b24884deda48bcc3f8", size = 264447, upload-time = "2026-05-26T20:41:17.369Z" }, + { url = "https://files.pythonhosted.org/packages/fb/71/59513f8710ed3e6b0ac0a050a5b7e977bb9c9e880354863b5d00d8809256/coverage-7.14.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9132cd363a68a4c3daa7c8704a654b1e39d3360f6f5b8ddd470608a945236c07", size = 262048, upload-time = "2026-05-26T20:41:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/bceed32dc494f5bbf50f775cd2e78ca814953942b5ea28d3c1c3ac316f14/coverage-7.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07c6290b1697b862c0478eab545eec949a0d0e4d6d03497f446d706da3b4f2de", size = 265781, upload-time = "2026-05-26T20:41:21.559Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c5/9348fe40dbfd4991aaf78df2c6c3098bfb2cc834d1fd362a64b4efef855a/coverage-7.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5ea0c297e27133853b4d8a3eb799bff5a2dbd9f2f41537a240d337ac9b4df890", size = 260896, upload-time = "2026-05-26T20:41:23.428Z" }, + { url = "https://files.pythonhosted.org/packages/ca/92/1ea0f03929da7cf87206b1fa24f4c8e9c158be0455481af29ec0a1f3503f/coverage-7.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:01b7733daad0237daa01ef80fe2dfceffc911e6a17fa7b55d14aa8214eaaaecd", size = 263214, upload-time = "2026-05-26T20:41:25.419Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a9/b2493c054c0e01a643266742ab45e15744e60743f9260cd930c7142b1124/coverage-7.14.1-cp314-cp314t-win32.whl", hash = "sha256:6adc5a36984624a70bf11d7184e20fa0a49aa7c47ffab43804106a1a695ea22e", size = 223624, upload-time = "2026-05-26T20:41:27.795Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bd/3e1e6a57fccd2d7c83fcdf338e93ba98eb85c6e877dd34731ac585375490/coverage-7.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ddf799247318f34dbcd2efa8c95a8d0642674e926bb1774cf9b63dfd2a389d1c", size = 224728, upload-time = "2026-05-26T20:41:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d7/31066cf1d2f0c6c797fce911bcfa01dd35642dc6da992a950256097c5860/coverage-7.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:145986fe66647eb489f18d9a997567a3fd358584c4b5a808769113abc07466af", size = 222752, upload-time = "2026-05-26T20:41:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3c/1a983b9a745d7f83d53f057bcc5bf79ba6a2bbc08266b3f0c7d6fe630c9b/coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2", size = 211815, upload-time = "2026-05-26T20:41:34.078Z" }, ] [[package]] name = "cryptography" -version = "46.0.7" +version = "48.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, - { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, - { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, - { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, - { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, - { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, - { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, - { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, - { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, - { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, - { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, - { url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" }, - { url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" }, - { url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" }, - { url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" }, - { url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" }, - { url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" }, - { url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" }, - { url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" }, - { url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" }, - { url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" }, - { url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, - { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, - { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, - { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, - { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, - { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, - { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, - { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" }, + { url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" }, + { url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" }, + { url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" }, + { url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" }, + { url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" }, + { url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" }, + { url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" }, + { url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" }, + { url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" }, + { url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" }, + { url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" }, + { url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" }, + { url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" }, + { url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" }, + { url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" }, + { url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" }, + { url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" }, + { url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" }, ] [[package]] @@ -541,11 +605,11 @@ wheels = [ [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, ] [[package]] @@ -559,7 +623,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.136.1" +version = "0.136.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -568,18 +632,18 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5d/45/c130091c2dfa061bbfe3150f2a5091ef1adf149f2a8d2ae769ecaf6e99a2/fastapi-0.136.1.tar.gz", hash = "sha256:7af665ad7acfa0a3baf8983d393b6b471b9da10ede59c60045f49fbc89a0fa7f", size = 397448, upload-time = "2026-04-23T16:49:44.046Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/2d/ff8d91d7b564d464629a0fd50a4489c97fcb836ac230bf3a7269232a9b1f/fastapi-0.136.3.tar.gz", hash = "sha256:e487fae93ad408e6f47641ee4dfe389864fd7bec92e547ea8498fc13f43e83ab", size = 396410, upload-time = "2026-05-23T18:53:15.192Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" }, + { url = "https://files.pythonhosted.org/packages/e0/82/45359b62a067409bd929ae8a56b8ed13e5a8c8a61194b3c236920999ab83/fastapi-0.136.3-py3-none-any.whl", hash = "sha256:3d2a69bdf04b7e9f3afa292c3bc7a98816bbfafa10bc9b45f3f3700d2f761620", size = 117481, upload-time = "2026-05-23T18:53:16.924Z" }, ] [[package]] name = "filelock" -version = "3.29.0" +version = "3.29.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +sdist = { url = "https://files.pythonhosted.org/packages/91/f5/3557bf28e0f1943e4849154c821533706e6dea010f96fb6aa0b6949037d1/filelock-3.29.3.tar.gz", hash = "sha256:7fc1b3f39cf172fd8203812043c57b8a65aef9969f38b6704f628b881f761a84", size = 61956, upload-time = "2026-06-10T17:37:11.832Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/81/8f/b61d427c4f49a8bdadc93f4e7e74df8a6df6f77ee6e26bf0df53d3925363/filelock-3.29.3-py3-none-any.whl", hash = "sha256:e58333029cc9b925f39aad59b1d8f0a1ad836af4e60d7217f4a4dba87461261d", size = 42324, upload-time = "2026-06-10T17:37:10.37Z" }, ] [[package]] @@ -657,39 +721,59 @@ wheels = [ [[package]] name = "greenlet" -version = "3.4.0" +version = "3.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/94/a5935717b307d7c71fe877b52b884c6af707d2d2090db118a03fbd799369/greenlet-3.4.0.tar.gz", hash = "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", size = 195913, upload-time = "2026-04-08T17:08:00.863Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/6e/802acd792aebb2256fbbee8cacf2727faaeb6f240ac11008f09eae4414bc/greenlet-3.5.1.tar.gz", hash = "sha256:5a56aeb7d5d9cc4b3a735efb5095bd4b4f6f0e4f93e5ca876d0e2315137b7829", size = 197356, upload-time = "2026-05-20T15:05:03.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/75/7e9cd1126a1e1f0cd67b0eda02e5221b28488d352684704a78ed505bd719/greenlet-3.4.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:43748988b097f9c6f09364f260741aa73c80747f63389824435c7a50bfdfd5c1", size = 285856, upload-time = "2026-04-08T15:52:45.82Z" }, - { url = "https://files.pythonhosted.org/packages/9d/c4/3e2df392e5cb199527c4d9dbcaa75c14edcc394b45040f0189f649631e3c/greenlet-3.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5566e4e2cd7a880e8c27618e3eab20f3494452d12fd5129edef7b2f7aa9a36d1", size = 610208, upload-time = "2026-04-08T16:24:39.674Z" }, - { url = "https://files.pythonhosted.org/packages/da/af/750cdfda1d1bd30a6c28080245be8d0346e669a98fdbae7f4102aa95fff3/greenlet-3.4.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1054c5a3c78e2ab599d452f23f7adafef55062a783a8e241d24f3b633ba6ff82", size = 621269, upload-time = "2026-04-08T16:30:59.767Z" }, - { url = "https://files.pythonhosted.org/packages/e0/93/c8c508d68ba93232784bbc1b5474d92371f2897dfc6bc281b419f2e0d492/greenlet-3.4.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:98eedd1803353daf1cd9ef23eef23eda5a4d22f99b1f998d273a8b78b70dd47f", size = 628455, upload-time = "2026-04-08T16:40:40.698Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/0cbc693622cd54ebe25207efbb3a0eb07c2639cb8594f6e3aaaa0bb077a8/greenlet-3.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f82cb6cddc27dd81c96b1506f4aa7def15070c3b2a67d4e46fd19016aacce6cf", size = 617549, upload-time = "2026-04-08T15:56:34.893Z" }, - { url = "https://files.pythonhosted.org/packages/7f/46/cfaaa0ade435a60550fd83d07dfd5c41f873a01da17ede5c4cade0b9bab8/greenlet-3.4.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:b7857e2202aae67bc5725e0c1f6403c20a8ff46094ece015e7d474f5f7020b55", size = 426238, upload-time = "2026-04-08T16:43:06.865Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c0/8966767de01343c1ff47e8b855dc78e7d1a8ed2b7b9c83576a57e289f81d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:227a46251ecba4ff46ae742bc5ce95c91d5aceb4b02f885487aff269c127a729", size = 1575310, upload-time = "2026-04-08T16:26:21.671Z" }, - { url = "https://files.pythonhosted.org/packages/b8/38/bcdc71ba05e9a5fda87f63ffc2abcd1f15693b659346df994a48c968003d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b99e87be7eba788dd5b75ba1cde5639edffdec5f91fe0d734a249535ec3408c", size = 1640435, upload-time = "2026-04-08T15:57:32.572Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c2/19b664b7173b9e4ef5f77e8cef9f14c20ec7fce7920dc1ccd7afd955d093/greenlet-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:849f8bc17acd6295fcb5de8e46d55cc0e52381c56eaf50a2afd258e97bc65940", size = 238760, upload-time = "2026-04-08T17:04:03.878Z" }, - { url = "https://files.pythonhosted.org/packages/9b/96/795619651d39c7fbd809a522f881aa6f0ead504cc8201c3a5b789dfaef99/greenlet-3.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9390ad88b652b1903814eaabd629ca184db15e0eeb6fe8a390bbf8b9106ae15a", size = 235498, upload-time = "2026-04-08T17:05:00.584Z" }, - { url = "https://files.pythonhosted.org/packages/78/02/bde66806e8f169cf90b14d02c500c44cdbe02c8e224c9c67bafd1b8cadd1/greenlet-3.4.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:10a07aca6babdd18c16a3f4f8880acfffc2b88dfe431ad6aa5f5740759d7d75e", size = 286291, upload-time = "2026-04-08T17:09:34.307Z" }, - { url = "https://files.pythonhosted.org/packages/05/1f/39da1c336a87d47c58352fb8a78541ce63d63ae57c5b9dae1fe02801bbc2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:076e21040b3a917d3ce4ad68fb5c3c6b32f1405616c4a57aa83120979649bd3d", size = 656749, upload-time = "2026-04-08T16:24:41.721Z" }, - { url = "https://files.pythonhosted.org/packages/d3/6c/90ee29a4ee27af7aa2e2ec408799eeb69ee3fcc5abcecac6ddd07a5cd0f2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e82689eea4a237e530bb5cb41b180ef81fa2160e1f89422a67be7d90da67f615", size = 669084, upload-time = "2026-04-08T16:31:01.372Z" }, - { url = "https://files.pythonhosted.org/packages/d2/4a/74078d3936712cff6d3c91a930016f476ce4198d84e224fe6d81d3e02880/greenlet-3.4.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:06c2d3b89e0c62ba50bd7adf491b14f39da9e7e701647cb7b9ff4c99bee04b19", size = 673405, upload-time = "2026-04-08T16:40:42.527Z" }, - { url = "https://files.pythonhosted.org/packages/07/49/d4cad6e5381a50947bb973d2f6cf6592621451b09368b8c20d9b8af49c5b/greenlet-3.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df3b0b2289ec686d3c821a5fee44259c05cfe824dd5e6e12c8e5f5df23085cf", size = 665621, upload-time = "2026-04-08T15:56:35.995Z" }, - { url = "https://files.pythonhosted.org/packages/79/3e/df8a83ab894751bc31e1106fdfaa80ca9753222f106b04de93faaa55feb7/greenlet-3.4.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:070b8bac2ff3b4d9e0ff36a0d19e42103331d9737e8504747cd1e659f76297bd", size = 471670, upload-time = "2026-04-08T16:43:08.512Z" }, - { url = "https://files.pythonhosted.org/packages/37/31/d1edd54f424761b5d47718822f506b435b6aab2f3f93b465441143ea5119/greenlet-3.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8bff29d586ea415688f4cec96a591fcc3bf762d046a796cdadc1fdb6e7f2d5bf", size = 1622259, upload-time = "2026-04-08T16:26:23.201Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c6/6d3f9cdcb21c4e12a79cb332579f1c6aa1af78eb68059c5a957c7812d95e/greenlet-3.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a569c2fb840c53c13a2b8967c63621fafbd1a0e015b9c82f408c33d626a2fda", size = 1686916, upload-time = "2026-04-08T15:57:34.282Z" }, - { url = "https://files.pythonhosted.org/packages/63/45/c1ca4a1ad975de4727e52d3ffe641ae23e1d7a8ffaa8ff7a0477e1827b92/greenlet-3.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:207ba5b97ea8b0b60eb43ffcacf26969dd83726095161d676aac03ff913ee50d", size = 239821, upload-time = "2026-04-08T17:03:48.423Z" }, - { url = "https://files.pythonhosted.org/packages/71/c4/6f621023364d7e85a4769c014c8982f98053246d142420e0328980933ceb/greenlet-3.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:f8296d4e2b92af34ebde81085a01690f26a51eb9ac09a0fcadb331eb36dbc802", size = 236932, upload-time = "2026-04-08T17:04:33.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/8f/18d72b629783f5e8d045a76f5325c1e938e659a9e4da79c7dcd10169a48d/greenlet-3.4.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d70012e51df2dbbccfaf63a40aaf9b40c8bed37c3e3a38751c926301ce538ece", size = 294681, upload-time = "2026-04-08T15:52:35.778Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ad/5fa86ec46769c4153820d58a04062285b3b9e10ba3d461ee257b68dcbf53/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a58bec0751f43068cd40cff31bb3ca02ad6000b3a51ca81367af4eb5abc480c8", size = 658899, upload-time = "2026-04-08T16:24:43.32Z" }, - { url = "https://files.pythonhosted.org/packages/43/f0/4e8174ca0e87ae748c409f055a1ba161038c43cc0a5a6f1433a26ac2e5bf/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05fa0803561028f4b2e3b490ee41216a842eaee11aed004cc343a996d9523aa2", size = 665284, upload-time = "2026-04-08T16:31:02.833Z" }, - { url = "https://files.pythonhosted.org/packages/ef/92/466b0d9afd44b8af623139a3599d651c7564fa4152f25f117e1ee5949ffb/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c4cd56a9eb7a6444edbc19062f7b6fbc8f287c663b946e3171d899693b1c19fa", size = 665872, upload-time = "2026-04-08T16:40:43.912Z" }, - { url = "https://files.pythonhosted.org/packages/19/da/991cf7cd33662e2df92a1274b7eb4d61769294d38a1bba8a45f31364845e/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e60d38719cb80b3ab5e85f9f1aed4960acfde09868af6762ccb27b260d68f4ed", size = 661861, upload-time = "2026-04-08T15:56:37.269Z" }, - { url = "https://files.pythonhosted.org/packages/0d/14/3395a7ef3e260de0325152ddfe19dffb3e49fe10873b94654352b53ad48e/greenlet-3.4.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:1f85f204c4d54134ae850d401fa435c89cd667d5ce9dc567571776b45941af72", size = 489237, upload-time = "2026-04-08T16:43:09.993Z" }, - { url = "https://files.pythonhosted.org/packages/36/c5/6c2c708e14db3d9caea4b459d8464f58c32047451142fe2cfd90e7458f41/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f50c804733b43eded05ae694691c9aa68bca7d0a867d67d4a3f514742a2d53f", size = 1622182, upload-time = "2026-04-08T16:26:24.777Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4c/50c5fed19378e11a29fabab1f6be39ea95358f4a0a07e115a51ca93385d8/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2d4f0635dc4aa638cda4b2f5a07ae9a2cff9280327b581a3fcb6f317b4fbc38a", size = 1685050, upload-time = "2026-04-08T15:57:36.453Z" }, - { url = "https://files.pythonhosted.org/packages/db/72/85ae954d734703ab48e622c59d4ce35d77ce840c265814af9c078cacc7aa/greenlet-3.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1a4a48f24681300c640f143ba7c404270e1ebbbcf34331d7104a4ff40f8ea705", size = 245554, upload-time = "2026-04-08T17:03:50.044Z" }, + { url = "https://files.pythonhosted.org/packages/27/69/7f7e5372d998b81001899b1c0823c957aa413ba0f2662e65821611cc31e4/greenlet-3.5.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:51518ff74664078fc51bffcc6fc529b0df5ae58da192691cee765d45ce944a2b", size = 285060, upload-time = "2026-05-20T13:08:51.899Z" }, + { url = "https://files.pythonhosted.org/packages/b1/bf/387f9b6b865fd2ae0d0be09e0004827295a01b71be76ed350dd1e28a91a4/greenlet-3.5.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ffdb3c0bb002c99cd8f298957e046c3dbf6006b5b7cdf11a4e19194624a0a0a", size = 604370, upload-time = "2026-05-20T14:00:07.492Z" }, + { url = "https://files.pythonhosted.org/packages/32/f5/169ce3d4e4c67291bd18f8cbe0299c9f3e45102c7f1fb3c14780c93e4532/greenlet-3.5.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7715a5a2c3378ba602c3a440558261e13a820bb53a82693aacd7b7f6d964e283", size = 616987, upload-time = "2026-05-20T14:05:44.237Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/c24110c55dffa55aa6e1d98b45310da33801aeba7686ff0190fe5d46fd32/greenlet-3.5.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d40a890035c0058cadbdc4af7569800fd28a0e527a0fdbb7b5f9418f176846ce", size = 622911, upload-time = "2026-05-20T14:09:10.598Z" }, + { url = "https://files.pythonhosted.org/packages/ee/e5/7f2e41d5273be07e77560d61ea4e56485b4d6c316d2a84518c62d1364061/greenlet-3.5.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc71ff466927a201b08305acac451ebe1aedfcea002f62f1f2f2ac2ac1e6a135", size = 613911, upload-time = "2026-05-20T13:14:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/ec/7b/d20db2e8a5ad6c038702f3179b136f93f0a3d1a21a0c0777f3e470cdf4b2/greenlet-3.5.1-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:67821bb03e4e98664490edb787ff6af501194c29bbee0f5c1dfdcf1dc3d9d436", size = 425228, upload-time = "2026-05-20T14:01:40.837Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a4/fbdc67579b73615a1f91615e814303cc71e06128f7baaba87be79b8fb90c/greenlet-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cd443683db272ebaaca03af98c0b063ab30db70ea8a31a1559f35e3f7b744ccd", size = 1570689, upload-time = "2026-05-20T14:02:27.225Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b4/77abbe35078be39718a46cd49caf16bceb35662f97a34101dca28aa98e47/greenlet-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:089fff7a6ce8d9316d1f65ebc00273a56be258c1725b32b94de90a3a979557e1", size = 1635602, upload-time = "2026-05-20T13:14:36.344Z" }, + { url = "https://files.pythonhosted.org/packages/37/f7/129f27ca700845b8ee8ca88ce7f43435a1239c2eddb7677fc938822762cf/greenlet-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:110a1ca7b49b014b097f6078272c3f4ed31af45b254de5228b79adba879f6af9", size = 238683, upload-time = "2026-05-20T13:11:50.57Z" }, + { url = "https://files.pythonhosted.org/packages/6d/5c/a485a36e87df8d8fd0632ee01511244f5156a20ed3746cc6599340326395/greenlet-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f16ba1efc0715b680a18b8123d90dad887c6112ae3555b4b5c32c149540c6b4e", size = 235499, upload-time = "2026-05-20T13:12:42.028Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cb/c62454606daf5640369c94d8a9dd540599b1bfc090e2d2180cb77f4038d2/greenlet-3.5.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8ab31c9de8651a2facdd5c5bb0011f2380dd1a7af78ce2adf4b56095294fc07", size = 285579, upload-time = "2026-05-20T13:08:56.396Z" }, + { url = "https://files.pythonhosted.org/packages/ec/71/c4270398c2eba968a6071af1dfbdcaeee6ec1c24bc8b435b8cc452700da6/greenlet-3.5.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e300185139abc337ade480c327183adf42a875ac7181bfe66d7d4efea31fbea", size = 651106, upload-time = "2026-05-20T14:00:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ab/71e34b78a44ec271fb5f550c17bc46d301ddc5953890d935f270b0dcdb5a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7ffdb990dcaa0234cf9845aead5df2e3c3a8b6507d409274dd87e0d5ab05ffc2", size = 663478, upload-time = "2026-05-20T14:05:45.88Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/2d80842910da44f78c286532d084b8a5c3717c844ae80ceb3858738ae89a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c09df69dc1712d131332054a858a3e5cca400967fa3a672e2324fbb0971448c", size = 667767, upload-time = "2026-05-20T14:09:12.15Z" }, + { url = "https://files.pythonhosted.org/packages/77/96/4efd6fa5c62c85426a0c19077a586258ebc3a2a146ff2493e4312a697a22/greenlet-3.5.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f82b3597e9d83b63408affed0b48fd0f54935edac4302237b9a837be0dae33c", size = 660800, upload-time = "2026-05-20T13:14:29.129Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d3/dad2eecedfbb1ed7050a20dcfae40c1442b74bc7423608be2c7e03ee7133/greenlet-3.5.1-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:a4764e0bfc6a4d114c865b32520805c16a990ef5f286a514413b05d5ecd6a23d", size = 470786, upload-time = "2026-05-20T14:01:42.064Z" }, + { url = "https://files.pythonhosted.org/packages/7a/e0/6c71401a25cac7000261304e866a2f2cc04dc74810d40e2f118aa4799495/greenlet-3.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c0141e37414c10164e702b8fb1473304221ad98f71600850c6ef7ff4880feba0", size = 1617518, upload-time = "2026-05-20T14:02:28.662Z" }, + { url = "https://files.pythonhosted.org/packages/41/26/c5c06643e8c0af9e7bf18e16cb51d0ab7625155f0392e1c9015d66d556cd/greenlet-3.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:50ae25a67bea74ea41fb14b960bc532df73eb713417b2d61892dced82fe8d3bc", size = 1681593, upload-time = "2026-05-20T13:14:39.417Z" }, + { url = "https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:8a17c42330e261299766b75ac1ea32caa437a9453c8f65d16a13140db378ecd3", size = 239800, upload-time = "2026-05-20T13:09:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/47/f8/8e8e8417b7bf28639a5a56356ef934d0375e1d0c70a57e04d7701e870ffe/greenlet-3.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:7b5f5fae05b8ac6d176a61b60c394a8cbdc2b5b91b81793066e68745cf165e54", size = 236862, upload-time = "2026-05-20T13:09:10.498Z" }, + { url = "https://files.pythonhosted.org/packages/90/12/41bf27fde4d3605d3773ae57751eda182b8be2f5398011c041173b1d9534/greenlet-3.5.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:ea8da1e900d758d078810d4255d8c6aa572181896a31ec79d779eb79c3adc9ad", size = 293637, upload-time = "2026-05-20T13:12:35.529Z" }, + { url = "https://files.pythonhosted.org/packages/44/44/ba14b23e9757707050c2f397d305bbcae62e5d7cad122f8b6baec5ae4a1f/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a19570c52a21420dcbc94e661994bc325c0b5b11304540fed514586da5dc8f2e", size = 650840, upload-time = "2026-05-20T14:00:11.079Z" }, + { url = "https://files.pythonhosted.org/packages/a8/37/5ddc2b686a6844f91abecef43411842426da2e1573f60b49ecf2547f4ae1/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d955c89b75eeca4723d7cc14135f393cd47c32e2a6cb4a8e4c6e760a26b0986", size = 656416, upload-time = "2026-05-20T14:05:47.118Z" }, + { url = "https://files.pythonhosted.org/packages/8c/46/5987dcd1a2570ba84f3b187536b2ca3ae97613387e57f5cfa99df068fe5e/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea37d5a157eb9493820d3792ac4ece28619a394391d2b9f2f78057d396ff0f0f", size = 656607, upload-time = "2026-05-20T14:09:13.949Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f0/d17510297c35a2992712f0bf84de3779749999f7d3d63aa1f09db7c62dbe/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2daaaebd1a5aa88c49045b6baf9310b3263796bd88db713edf37cf53e7bb4e", size = 654397, upload-time = "2026-05-20T13:14:30.696Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c1/6da0a9ddcc29d7e51ef14883fa3dc1e53b3f4ffba00582106c7bf55da1d8/greenlet-3.5.1-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:8d8a23250ea3ec7b36de8fa4b541e9e2db3ee82915cc060ab0631609ad8b28de", size = 488287, upload-time = "2026-05-20T14:01:43.143Z" }, + { url = "https://files.pythonhosted.org/packages/37/eb/147387705bb89092645b012586e7273cb5ed3c90ef7eaf3a69173eaf0209/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bfbd69cc349e43bf3a8ae1c85548ff0718efc887615c2db16c3833d7b0b072d", size = 1614469, upload-time = "2026-05-20T14:02:30.192Z" }, + { url = "https://files.pythonhosted.org/packages/a6/4e/37ee0da7732b7aa9896f17e15579a9df34b9fcb9dd494f0adfa749af6623/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4378720dd888136c27215a0214d32a4d37c3852765d45bc37aad0623423cfd78", size = 1675115, upload-time = "2026-05-20T13:14:40.972Z" }, + { url = "https://files.pythonhosted.org/packages/57/f3/97dfcf4a6eb5077f8a672234216fb5923eb89f2cab7081cb10b2cf75b605/greenlet-3.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:45718441607f9325d948db98cbc691276059316d0358c188c246da4e1d4d23d2", size = 245246, upload-time = "2026-05-20T13:12:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/5d/73/d7f72e34b582f694f4a9b248162db7b09cc458a259ba8f0c0bfa1a34ea7d/greenlet-3.5.1-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:2baee5ca02031757ffe8cc3d69f0cc0aec7065ce362622da74f32d3bcab1c541", size = 285575, upload-time = "2026-05-20T13:12:07.043Z" }, + { url = "https://files.pythonhosted.org/packages/df/59/fa9c6e87dc8ad27a95dabe2f29f372b733d05a8a67470f6c901ed9975655/greenlet-3.5.1-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1ec3274918a81d3ea778b9e75b56b72b33f300edb6cf7f3a7fe1dae56683de", size = 656428, upload-time = "2026-05-20T14:00:12.556Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f9/e753408871eaa61dfe35e619cfc67512b036fde99893685d50eea9e07146/greenlet-3.5.1-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:111e2390ffffc47d5840b01711dd7fac07d4c09283d0283e7f3264b14e284c64", size = 667064, upload-time = "2026-05-20T14:05:48.662Z" }, + { url = "https://files.pythonhosted.org/packages/dc/74/807a047255bf1e09303627c46dc043dca596b6958a354d904f32ab382005/greenlet-3.5.1-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:10a9a1c0bfbc93d41156ffcb90c75fbc05544054faf15dcc1fdf9765f8b607f0", size = 672962, upload-time = "2026-05-20T14:09:15.532Z" }, + { url = "https://files.pythonhosted.org/packages/96/27/5565b5b40389f1c7753003a07e21892fda8660926787036d5bc0308b8113/greenlet-3.5.1-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e630136e905fe5ff43e86945ae41220b6d1470956a39220e708110ac48d01ea5", size = 665697, upload-time = "2026-05-20T13:14:32.943Z" }, + { url = "https://files.pythonhosted.org/packages/76/32/19d4e13225193c29b13e308015223f7d75fd3d8623d49dd19040d2ce8ec1/greenlet-3.5.1-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:ef08c1567c78074b22d1a200183d52d04a14df447bf70bcbb6a3507a48e776fc", size = 476047, upload-time = "2026-05-20T14:01:44.39Z" }, + { url = "https://files.pythonhosted.org/packages/cf/82/e7de4178c0c2d1c9a5a3be3cc0b33e46a85b3ee4a77c071bf7ad8600e079/greenlet-3.5.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:975eac34b44a7077ca4d421348455b94f0f518246a7f14bc6d2fdcfe5b584368", size = 1621256, upload-time = "2026-05-20T14:02:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/00/10/f2dddcf7dacac17dfc68691809589adad06135eb28930429cf58a6467a2f/greenlet-3.5.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:9ab3c3a0b2ae6198e67c898dad5215a49f9ae0d0081b3c3ec59f333e39eeca26", size = 1685956, upload-time = "2026-05-20T13:14:42.55Z" }, + { url = "https://files.pythonhosted.org/packages/22/17/4a232b32133230ada52f70e9d7f5b65b0caef8772f01849bd8d149e7e4ca/greenlet-3.5.1-cp315-cp315-win_amd64.whl", hash = "sha256:cbfc69be86e10dcfef5b1e6269d1d6926552aa89ee39e1de3353360c1b6989ab", size = 239802, upload-time = "2026-05-20T13:13:15.481Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ae/4e623a7e6d4d2a5f4cb8e4c82de4169fc637942caae68d6e676b8a128ac5/greenlet-3.5.1-cp315-cp315-win_arm64.whl", hash = "sha256:92fd6d44ac5e5a887c8a5dc4a8ba0ba908527c31c12f78c6bc7dcfe8aab279f6", size = 236853, upload-time = "2026-05-20T13:15:37.301Z" }, + { url = "https://files.pythonhosted.org/packages/7a/57/816d9cff29119da3505b3d6a5e14a8af89006ac36f47f891ff293ee05af1/greenlet-3.5.1-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:a6fdf2433a5441ef9a95464f7c3e674775da1c8c1177fff311cee1acad4626ed", size = 293877, upload-time = "2026-05-20T13:10:19.078Z" }, + { url = "https://files.pythonhosted.org/packages/23/a1/59b0a7c7d140ff1a75626680b9a9899b79a9176cab298b394968fb023295/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7546556f0d649f99f6a361098a55f761181bb2ea12ff150bb16d26092ad88244", size = 655333, upload-time = "2026-05-20T14:00:14.758Z" }, + { url = "https://files.pythonhosted.org/packages/72/1b/5efe127597625042218939d01855109f352779050768b670b52edcc16a6c/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5ee3ea898009fa898f85f9982255d35278c477bebe185beca249cab42d4526c", size = 659443, upload-time = "2026-05-20T14:05:50.159Z" }, + { url = "https://files.pythonhosted.org/packages/c9/9d/1dcdf7b95ab3cf8c7b6d7277c18a5e167312f2b362ddfcc5d5e6d8d84b43/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a57b0d05a0448eed231d59c0ceb287dde984551e54cbc51ac2d4865712838e9c", size = 659998, upload-time = "2026-05-20T14:09:16.912Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6d/c404246ea4d22d097a7426d0efb5b781bd7eb67715f09e79001bd552ab18/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5c81f74d204d3edd136ebfd50dce53acbb776995d721a0fe801626cfc93b8cd", size = 658356, upload-time = "2026-05-20T13:14:35.091Z" }, + { url = "https://files.pythonhosted.org/packages/05/7e/c4959664fc231d587d66d8e81f2095e98056ba1954beafdcbe635e251052/greenlet-3.5.1-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:b0703c2cef53e01baec47f7a3868009913ad71ec678bbecb42a6f40895e4ce62", size = 494470, upload-time = "2026-05-20T14:01:45.611Z" }, + { url = "https://files.pythonhosted.org/packages/51/02/f8ee37fb6d2219329f350af241c27fcf12df57e723d11f6fc6d3bacdadaa/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:2c18ef16bf6d4dd410e4dd52996888ea1497be26892fe5bbc73580aba4287b8e", size = 1619216, upload-time = "2026-05-20T14:02:33.403Z" }, + { url = "https://files.pythonhosted.org/packages/93/c5/3dc9475ace2c7a3680da12372cddd7f1ac874eb410a1ac48d3e9dab83782/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:17d86354f0ae6b61bf9be5148d0dd34e06c3cb7c602c671f79f29ac3b150e659", size = 1678427, upload-time = "2026-05-20T13:14:43.71Z" }, + { url = "https://files.pythonhosted.org/packages/df/4e/750c15c317a41ffb36f0bf40b933e3d744a7dede61889f74443ea69690cf/greenlet-3.5.1-cp315-cp315t-win_amd64.whl", hash = "sha256:e7516cf6ae6b8a582c2770a0caed47b8a48373ed732c33d69a72913ae6ac923e", size = 245225, upload-time = "2026-05-20T13:13:59.366Z" }, + { url = "https://files.pythonhosted.org/packages/4f/fd/d3baea2eeb7b617efd47e87ca06e2ec2c6118d303aa9e918e0ce16eadc10/greenlet-3.5.1-cp315-cp315t-win_arm64.whl", hash = "sha256:5028648bf2253ec4745add746129d3904121fa7fe871a76bed23c5720573ce0a", size = 239590, upload-time = "2026-05-20T13:13:37.382Z" }, ] [[package]] @@ -729,24 +813,31 @@ wheels = [ [[package]] name = "httptools" -version = "0.7.1" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, - { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, - { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, - { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, - { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, - { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, - { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, - { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, - { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, - { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, - { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, - { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, - { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e5/8cfcabc5546e8022f168be28bcdaa128a240a0befdd03b59d558b4f18bd6/httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8", size = 205148, upload-time = "2026-05-25T22:17:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c", size = 111368, upload-time = "2026-05-25T22:17:17.586Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/46f1cecf06b9bbde8e4b8c88034ac7908989e5ff7a3a388ef38392949c1f/httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7", size = 486447, upload-time = "2026-05-25T22:17:18.564Z" }, + { url = "https://files.pythonhosted.org/packages/77/00/258bfc0837221f81d9725c45f9b948a6a6b2994a147a4fb66e85100c668f/httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d", size = 482448, upload-time = "2026-05-25T22:17:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/04/ab/d1cef3b5523f4d272a70f42a776c3169a2dddfe3a54de4b2ce4a36341528/httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681", size = 464460, upload-time = "2026-05-25T22:17:20.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/5d1d072442277bb2b3434e0e60690b8e8c23840ef7de8b6ea54040a536d3/httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683", size = 471312, upload-time = "2026-05-25T22:17:22.085Z" }, + { url = "https://files.pythonhosted.org/packages/0d/66/b96623b27e51a68199ef4efdda0613cced9233fe3062ac74e50749c5ad37/httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1", size = 90117, upload-time = "2026-05-25T22:17:23.074Z" }, + { url = "https://files.pythonhosted.org/packages/1a/12/fa3fbf5f9517b273edea2dc982aa82a8c634091e67c590792b729017bc6f/httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6", size = 206183, upload-time = "2026-05-25T22:17:24.004Z" }, + { url = "https://files.pythonhosted.org/packages/30/fc/5e7c4cb443370f2090a3aba0453a07384d29ff66b7435bb90e77e1037599/httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b", size = 112079, upload-time = "2026-05-25T22:17:25.216Z" }, + { url = "https://files.pythonhosted.org/packages/ba/53/771bd891eb0f236f32145d6a1775777ec85745f3cc983a1f23d1a3b8ddfe/httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0", size = 481596, upload-time = "2026-05-25T22:17:26.186Z" }, + { url = "https://files.pythonhosted.org/packages/62/42/94e15bc68ce3d423243c45d7f1b0c7561f13844f97dc52ae23182fb65628/httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e", size = 480865, upload-time = "2026-05-25T22:17:27.542Z" }, + { url = "https://files.pythonhosted.org/packages/1c/7c/fe2980fc03723272e30f135b62360b075f513dfe7cc73aef36c7f04012bd/httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b", size = 463189, upload-time = "2026-05-25T22:17:28.546Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/47fc5fff68acd1bfa20b4734059c9a06cadb88119dcd5258b5b0d21d91c8/httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0", size = 466610, upload-time = "2026-05-25T22:17:29.816Z" }, + { url = "https://files.pythonhosted.org/packages/60/bd/07b13c93ffd9bec9546e0d43f8e19378dd696dbd278511406bc07371ef1f/httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527", size = 92705, upload-time = "2026-05-25T22:17:31.133Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c4/121648f68ce066d7bd762d6b6d97e620847642d38d54f3d90ff11d947629/httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568", size = 215023, upload-time = "2026-05-25T22:17:32.401Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b", size = 117405, upload-time = "2026-05-25T22:17:33.742Z" }, + { url = "https://files.pythonhosted.org/packages/fc/37/fccd705f795386bb05bf413012fecff2a33e5aa8c2f069096de3e9fd8702/httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca", size = 558497, upload-time = "2026-05-25T22:17:34.732Z" }, + { url = "https://files.pythonhosted.org/packages/bd/39/f172e8003576de35f5ba77ff417cf0e34429d35dc014deef15afa337a72c/httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f", size = 571585, upload-time = "2026-05-25T22:17:35.813Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b9/f5564760af99f3dbbf3f9104dc00e5da27e96cf433c6bdcf77617f70bf3f/httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d", size = 543297, upload-time = "2026-05-25T22:17:37.08Z" }, + { url = "https://files.pythonhosted.org/packages/99/67/8d9f2c313618e161b82f3873188e7196126da1d6e29688df40eb3997c77a/httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081", size = 539535, upload-time = "2026-05-25T22:17:38.032Z" }, + { url = "https://files.pythonhosted.org/packages/48/63/b906c01e53f50d432c0defe43ce52764a111dc1bdd028bafbeb54dcfd008/httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77", size = 108209, upload-time = "2026-05-25T22:17:39.473Z" }, ] [[package]] @@ -775,11 +866,11 @@ wheels = [ [[package]] name = "idna" -version = "3.11" +version = "3.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, ] [[package]] @@ -793,56 +884,103 @@ wheels = [ [[package]] name = "jiter" -version = "0.14.0" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/c1/0cddc6eb17d4c53a99840953f95dd3accdc5cfc7a337b0e9b26476276be9/jiter-0.14.0.tar.gz", hash = "sha256:e8a39e66dac7153cf3f964a12aad515afa8d74938ec5cc0018adcdae5367c79e", size = 165725, upload-time = "2026-04-10T14:28:42.01Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/b5/55f06bb281d92fb3cc86d14e1def2bd908bb77693183e7cb1f5a3c388b0c/jiter-0.15.0.tar.gz", hash = "sha256:4251acc80e2b7c9b7b8823456ea0fceeb0734dac2df7636d3c711b38476b5a76", size = 166640, upload-time = "2026-05-19T10:09:48.361Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/2a/09f70020898507a89279659a1afe3364d57fc1b2c89949081975d135f6f5/jiter-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:af72f204cf4d44258e5b4c1745130ac45ddab0e71a06333b01de660ab4187a94", size = 315502, upload-time = "2026-04-10T14:26:47.697Z" }, - { url = "https://files.pythonhosted.org/packages/d6/be/080c96a45cd74f9fce5db4fd68510b88087fb37ffe2541ff73c12db92535/jiter-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4b77da71f6e819be5fbcec11a453fde5b1d0267ef6ed487e2a392fd8e14e4e3a", size = 314870, upload-time = "2026-04-10T14:26:49.149Z" }, - { url = "https://files.pythonhosted.org/packages/7d/5e/2d0fee155826a968a832cc32438de5e2a193292c8721ca70d0b53e58245b/jiter-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f4ea612fe8b84b8b04e51d0e78029ecf3466348e25973f953de6e6a59aa4c1", size = 343406, upload-time = "2026-04-10T14:26:50.762Z" }, - { url = "https://files.pythonhosted.org/packages/70/af/bf9ee0d3a4f8dc0d679fc1337f874fe60cdbf841ebbb304b374e1c9aaceb/jiter-0.14.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62fe2451f8fcc0240261e6a4df18ecbcd58327857e61e625b2393ea3b468aac9", size = 369415, upload-time = "2026-04-10T14:26:52.188Z" }, - { url = "https://files.pythonhosted.org/packages/0f/83/8e8561eadba31f4d3948a5b712fb0447ec71c3560b57a855449e7b8ddc98/jiter-0.14.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6112f26f5afc75bcb475787d29da3aa92f9d09c7858f632f4be6ffe607be82e9", size = 461456, upload-time = "2026-04-10T14:26:53.611Z" }, - { url = "https://files.pythonhosted.org/packages/f6/c9/c5299e826a5fe6108d172b344033f61c69b1bb979dd8d9ddd4278a160971/jiter-0.14.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:215a6cb8fb7dc702aa35d475cc00ddc7f970e5c0b1417fb4b4ac5d82fa2a29db", size = 378488, upload-time = "2026-04-10T14:26:55.211Z" }, - { url = "https://files.pythonhosted.org/packages/5d/37/c16d9d15c0a471b8644b1abe3c82668092a707d9bedcf076f24ff2e380cd/jiter-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ab96a30fb3cb2c7e0cd33f7616c8860da5f5674438988a54ac717caccdbaa", size = 353242, upload-time = "2026-04-10T14:26:56.705Z" }, - { url = "https://files.pythonhosted.org/packages/58/ea/8050cb0dc654e728e1bfacbc0c640772f2181af5dedd13ae70145743a439/jiter-0.14.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:3a99c1387b1f2928f799a9de899193484d66206a50e98233b6b088a7f0c1edb2", size = 356823, upload-time = "2026-04-10T14:26:58.281Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3b/cf71506d270e5f84d97326bf220e47aed9b95e9a4a060758fb07772170ab/jiter-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab18d11074485438695f8d34a1b6da61db9754248f96d51341956607a8f39985", size = 392564, upload-time = "2026-04-10T14:27:00.018Z" }, - { url = "https://files.pythonhosted.org/packages/b0/cc/8c6c74a3efb5bd671bfd14f51e8a73375464ca914b1551bc3b40e26ac2c9/jiter-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:801028dcfc26ac0895e4964cbc0fd62c73be9fd4a7d7b1aaf6e5790033a719b7", size = 520322, upload-time = "2026-04-10T14:27:01.664Z" }, - { url = "https://files.pythonhosted.org/packages/41/24/68d7b883ec959884ddf00d019b2e0e82ba81b167e1253684fa90519ce33c/jiter-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ad425b087aafb4a1c7e1e98a279200743b9aaf30c3e0ba723aec93f061bd9bc8", size = 552619, upload-time = "2026-04-10T14:27:03.316Z" }, - { url = "https://files.pythonhosted.org/packages/b6/89/b1a0985223bbf3150ff9e8f46f98fc9360c1de94f48abe271bbe1b465682/jiter-0.14.0-cp313-cp313-win32.whl", hash = "sha256:882bcb9b334318e233950b8be366fe5f92c86b66a7e449e76975dfd6d776a01f", size = 205699, upload-time = "2026-04-10T14:27:04.662Z" }, - { url = "https://files.pythonhosted.org/packages/4c/19/3f339a5a7f14a11730e67f6be34f9d5105751d547b615ef593fa122a5ded/jiter-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:9b8c571a5dba09b98bd3462b5a53f27209a5cbbe85670391692ede71974e979f", size = 201323, upload-time = "2026-04-10T14:27:06.139Z" }, - { url = "https://files.pythonhosted.org/packages/50/56/752dd89c84be0e022a8ea3720bcfa0a8431db79a962578544812ce061739/jiter-0.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:34f19dcc35cb1abe7c369b3756babf8c7f04595c0807a848df8f26ef8298ef92", size = 191099, upload-time = "2026-04-10T14:27:07.564Z" }, - { url = "https://files.pythonhosted.org/packages/91/28/292916f354f25a1fe8cf2c918d1415c699a4a659ae00be0430e1c5d9ffea/jiter-0.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e89bcd7d426a75bb4952c696b267075790d854a07aad4c9894551a82c5b574ab", size = 320880, upload-time = "2026-04-10T14:27:09.326Z" }, - { url = "https://files.pythonhosted.org/packages/ad/c7/b002a7d8b8957ac3d469bd59c18ef4b1595a5216ae0de639a287b9816023/jiter-0.14.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b25beaa0d4447ea8c7ae0c18c688905d34840d7d0b937f2f7bdd52162c98a40", size = 346563, upload-time = "2026-04-10T14:27:11.287Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3b/f8d07580d8706021d255a6356b8fab13ee4c869412995550ce6ed4ddf97d/jiter-0.14.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a8758dd413c51e3b7f6557cdc6921faf70b14106f45f969f091f5cda990ea", size = 357928, upload-time = "2026-04-10T14:27:12.729Z" }, - { url = "https://files.pythonhosted.org/packages/47/5b/ac1a974da29e35507230383110ffec59998b290a8732585d04e19a9eb5ba/jiter-0.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e1a7eead856a5038a8d291f1447176ab0b525c77a279a058121b5fccee257f6f", size = 203519, upload-time = "2026-04-10T14:27:14.125Z" }, - { url = "https://files.pythonhosted.org/packages/96/6d/9fc8433d667d2454271378a79747d8c76c10b51b482b454e6190e511f244/jiter-0.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e692633a12cda97e352fdcd1c4acc971b1c28707e1e33aeef782b0cbf051975", size = 190113, upload-time = "2026-04-10T14:27:16.638Z" }, - { url = "https://files.pythonhosted.org/packages/4f/1e/354ed92461b165bd581f9ef5150971a572c873ec3b68a916d5aa91da3cc2/jiter-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:6f396837fc7577871ca8c12edaf239ed9ccef3bbe39904ae9b8b63ce0a48b140", size = 315277, upload-time = "2026-04-10T14:27:18.109Z" }, - { url = "https://files.pythonhosted.org/packages/a6/95/8c7c7028aa8636ac21b7a55faef3e34215e6ed0cbf5ae58258427f621aa3/jiter-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a4d50ea3d8ba4176f79754333bd35f1bbcd28e91adc13eb9b7ca91bc52a6cef9", size = 315923, upload-time = "2026-04-10T14:27:19.603Z" }, - { url = "https://files.pythonhosted.org/packages/47/40/e2a852a44c4a089f2681a16611b7ce113224a80fd8504c46d78491b47220/jiter-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce17f8a050447d1b4153bda4fb7d26e6a9e74eb4f4a41913f30934c5075bf615", size = 344943, upload-time = "2026-04-10T14:27:21.262Z" }, - { url = "https://files.pythonhosted.org/packages/fc/1f/670f92adee1e9895eac41e8a4d623b6da68c4d46249d8b556b60b63f949e/jiter-0.14.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4f1c4b125e1652aefbc2e2c1617b60a160ab789d180e3d423c41439e5f32850", size = 369725, upload-time = "2026-04-10T14:27:22.766Z" }, - { url = "https://files.pythonhosted.org/packages/01/2f/541c9ba567d05de1c4874a0f8f8c5e3fd78e2b874266623da9a775cf46e0/jiter-0.14.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be808176a6a3a14321d18c603f2d40741858a7c4fc982f83232842689fe86dd9", size = 461210, upload-time = "2026-04-10T14:27:24.315Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a9/c31cbec09627e0d5de7aeaec7690dba03e090caa808fefd8133137cf45bc/jiter-0.14.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26679d58ba816f88c3849306dd58cb863a90a1cf352cdd4ef67e30ccf8a77994", size = 380002, upload-time = "2026-04-10T14:27:26.155Z" }, - { url = "https://files.pythonhosted.org/packages/50/02/3c05c1666c41904a2f607475a73e7a4763d1cbde2d18229c4f85b22dc253/jiter-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80381f5a19af8fa9aef743f080e34f6b25ebd89656475f8cf0470ec6157052aa", size = 354678, upload-time = "2026-04-10T14:27:27.701Z" }, - { url = "https://files.pythonhosted.org/packages/7d/97/e15b33545c2b13518f560d695f974b9891b311641bdcf178d63177e8801e/jiter-0.14.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:004df5fdb8ecbd6d99f3227df18ba1a259254c4359736a2e6f036c944e02d7c5", size = 358920, upload-time = "2026-04-10T14:27:29.256Z" }, - { url = "https://files.pythonhosted.org/packages/ad/d2/8b1461def6b96ba44530df20d07ef7a1c7da22f3f9bf1727e2d611077bf1/jiter-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cff5708f7ed0fa098f2b53446c6fa74c48469118e5cd7497b4f1cd569ab06928", size = 394512, upload-time = "2026-04-10T14:27:31.344Z" }, - { url = "https://files.pythonhosted.org/packages/e3/88/837566dd6ed6e452e8d3205355afd484ce44b2533edfa4ed73a298ea893e/jiter-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:2492e5f06c36a976d25c7cc347a60e26d5470178d44cde1b9b75e60b4e519f28", size = 521120, upload-time = "2026-04-10T14:27:33.299Z" }, - { url = "https://files.pythonhosted.org/packages/89/6b/b00b45c4d1b4c031777fe161d620b755b5b02cdade1e316dcb46e4471d63/jiter-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:7609cfbe3a03d37bfdbf5052012d5a879e72b83168a363deae7b3a26564d57de", size = 553668, upload-time = "2026-04-10T14:27:34.868Z" }, - { url = "https://files.pythonhosted.org/packages/ad/d8/6fe5b42011d19397433d345716eac16728ac241862a2aac9c91923c7509a/jiter-0.14.0-cp314-cp314-win32.whl", hash = "sha256:7282342d32e357543565286b6450378c3cd402eea333fc1ebe146f1fabb306fc", size = 207001, upload-time = "2026-04-10T14:27:36.455Z" }, - { url = "https://files.pythonhosted.org/packages/e5/43/5c2e08da1efad5e410f0eaaabeadd954812612c33fbbd8fd5328b489139d/jiter-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:bd77945f38866a448e73b0b7637366afa814d4617790ecd88a18ca74377e6c02", size = 202187, upload-time = "2026-04-10T14:27:38Z" }, - { url = "https://files.pythonhosted.org/packages/aa/1f/6e39ac0b4cdfa23e606af5b245df5f9adaa76f35e0c5096790da430ca506/jiter-0.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:f2d4c61da0821ee42e0cdf5489da60a6d074306313a377c2b35af464955a3611", size = 192257, upload-time = "2026-04-10T14:27:39.504Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1bf7ff85517dd2f20a5750081d2b75083c1b269cf75afc7511bdf1f9548beb3b", size = 323441, upload-time = "2026-04-10T14:27:41.039Z" }, - { url = "https://files.pythonhosted.org/packages/83/6e/7b3314398d8983f06b557aa21b670511ec72d3b79a68ee5e4d9bff972286/jiter-0.14.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8ef8791c3e78d6c6b157c6d360fbb5c715bebb8113bc6a9303c5caff012754a", size = 348109, upload-time = "2026-04-10T14:27:42.552Z" }, - { url = "https://files.pythonhosted.org/packages/ae/4f/8dc674bcd7db6dba566de73c08c763c337058baff1dbeb34567045b27cdc/jiter-0.14.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e74663b8b10da1fe0f4e4703fd7980d24ad17174b6bb35d8498d6e3ebce2ae6a", size = 368328, upload-time = "2026-04-10T14:27:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/3b/5f/188e09a1f20906f98bbdec44ed820e19f4e8eb8aff88b9d1a5a497587ff3/jiter-0.14.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1aca29ba52913f78362ec9c2da62f22cdc4c3083313403f90c15460979b84d9b", size = 463301, upload-time = "2026-04-10T14:27:46.717Z" }, - { url = "https://files.pythonhosted.org/packages/ac/f0/19046ef965ed8f349e8554775bb12ff4352f443fbe12b95d31f575891256/jiter-0.14.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b39b7d87a952b79949af5fef44d2544e58c21a28da7f1bae3ef166455c61746", size = 378891, upload-time = "2026-04-10T14:27:48.32Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c3/da43bd8431ee175695777ee78cf0e93eacbb47393ff493f18c45231b427d/jiter-0.14.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d918a68b26e9fab068c2b5453577ef04943ab2807b9a6275df2a812599a310", size = 360749, upload-time = "2026-04-10T14:27:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/72/26/e054771be889707c6161dbdec9c23d33a9ec70945395d70f07cfea1e9a6f/jiter-0.14.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:b08997c35aee1201c1a5361466a8fb9162d03ae7bf6568df70b6c859f1e654a4", size = 358526, upload-time = "2026-04-10T14:27:51.504Z" }, - { url = "https://files.pythonhosted.org/packages/c3/0f/7bea65ea2a6d91f2bf989ff11a18136644392bf2b0497a1fa50934c30a9c/jiter-0.14.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:260bf7ca20704d58d41f669e5e9fe7fe2fa72901a6b324e79056f5d52e9c9be2", size = 393926, upload-time = "2026-04-10T14:27:53.368Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/b1ff7d70deef61ac0b7c6c2f12d2ace950cdeecb4fdc94500a0926802857/jiter-0.14.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:37826e3df29e60f30a382f9294348d0238ef127f4b5d7f5f8da78b5b9e050560", size = 521052, upload-time = "2026-04-10T14:27:55.058Z" }, - { url = "https://files.pythonhosted.org/packages/0b/7b/3b0649983cbaf15eda26a414b5b1982e910c67bd6f7b1b490f3cfc76896a/jiter-0.14.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:645be49c46f2900937ba0eaf871ad5183c96858c0af74b6becc7f4e367e36e06", size = 553716, upload-time = "2026-04-10T14:27:57.269Z" }, - { url = "https://files.pythonhosted.org/packages/97/f8/33d78c83bd93ae0c0af05293a6660f88a1977caef39a6d72a84afab94ce0/jiter-0.14.0-cp314-cp314t-win32.whl", hash = "sha256:2f7877ed45118de283786178eceaf877110abacd04fde31efff3940ae9672674", size = 207957, upload-time = "2026-04-10T14:27:59.285Z" }, - { url = "https://files.pythonhosted.org/packages/d6/ac/2b760516c03e2227826d1f7025d89bf6bf6357a28fe75c2a2800873c50bf/jiter-0.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:14c0cb10337c49f5eafe8e7364daca5e29a020ea03580b8f8e6c597fed4e1588", size = 204690, upload-time = "2026-04-10T14:28:00.962Z" }, - { url = "https://files.pythonhosted.org/packages/dc/2e/a44c20c58aeed0355f2d326969a181696aeb551a25195f47563908a815be/jiter-0.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5419d4aa2024961da9fe12a9cfe7484996735dca99e8e090b5c88595ef1951ff", size = 191338, upload-time = "2026-04-10T14:28:02.853Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f4/f708c900ecee41b2025ef8413d5351e5649eb2125c506f6720cc69b06f5c/jiter-0.15.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1c11465f97e2abf45a014b83b730222f8f1c5335e802c7055a67d50de6f1f4e3", size = 307829, upload-time = "2026-05-19T10:07:59.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/59/db537c0949e83668c38481d426b9f2fd5ab758c4ee53a811dd0a510626a0/jiter-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d1e7b1776f0797956c509e123d0952d10d293a9492dea9f288ab9570ec01d1a5", size = 308445, upload-time = "2026-05-19T10:08:01.184Z" }, + { url = "https://files.pythonhosted.org/packages/37/38/ea0e13b18c30ef951da0d47d39e7fa9edb82a93a62990ffbd7cea9b622d4/jiter-0.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a341c2105aa430b7047e30f1bf7975f6313b00165d3fc07be2edaf741f279", size = 336181, upload-time = "2026-05-19T10:08:02.688Z" }, + { url = "https://files.pythonhosted.org/packages/58/fc/2303901b16c4ba05865588990a420c0b4156270b44379c20931544a1d962/jiter-0.15.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ab395feec8d249ec4044e228e98a7033f043426a265df439dc3698823f0a4e4", size = 362985, upload-time = "2026-05-19T10:08:04.394Z" }, + { url = "https://files.pythonhosted.org/packages/5b/6f/11bace093c52e7d4d26c8e606ccd7ae8c972189622469ec0d9e28161e28b/jiter-0.15.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2a438005b6f22d0273413484d6094d7c2c5d10ec1b3a3bf128e0d1d3ba53258", size = 453292, upload-time = "2026-05-19T10:08:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/22/db/987f2f086ca4d7a6582eb4ccd513f9b26b42d9e4243a087609a3137a8fc7/jiter-0.15.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f18f85e4218d1b40f000f42a92239a7a61a902cd42c65e6c360dbd17dcb20894", size = 373501, upload-time = "2026-05-19T10:08:07.857Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7c/89fbcabb2739b7a5b8dc959a1b6c5761f6484f5fed3486854b3c789bb1de/jiter-0.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1aa62e277fc1cbd80e6deacae6f4d983b41b3d7728e0645c5d741a6149bba45", size = 344683, upload-time = "2026-05-19T10:08:09.431Z" }, + { url = "https://files.pythonhosted.org/packages/30/6f/6cca7692e7dddfec6d8d76c54dc97f2af2a41df4ac0674b999df1f09a5f3/jiter-0.15.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:6550fa135c7deb8ead6af49ed7ff648532ea8334a1447fe34a36315ef79c5c29", size = 350892, upload-time = "2026-05-19T10:08:11.352Z" }, + { url = "https://files.pythonhosted.org/packages/39/14/0338d6190cb8e6d22e677ab1d4eabd4117f67cca70c54cd04b82ff64e068/jiter-0.15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:066f8f33f18b2419cd8213b2436fa7fbc9c499f315971cfa3ce1f9820c001b1b", size = 388723, upload-time = "2026-05-19T10:08:12.912Z" }, + { url = "https://files.pythonhosted.org/packages/90/31/cc19f4a1bdb6afb09ce6a2f2615aa8d44d994eba0d8e6105ed1af920e736/jiter-0.15.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:75e8a04e91432dde9f1838373cf93d23726c79d3e908d319acf0e796f85592e7", size = 516648, upload-time = "2026-05-19T10:08:14.808Z" }, + { url = "https://files.pythonhosted.org/packages/49/9f/833c541512cd091b63c10c0381973dfe11bc7a503a818c16384417e0c81e/jiter-0.15.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a97261f1fccb8e50ecd2890a96e46efdc3f57c80a197324c6777827231eca712", size = 547382, upload-time = "2026-05-19T10:08:16.927Z" }, + { url = "https://files.pythonhosted.org/packages/d2/11/e7b70e91f90bc4477e8eee9e8a5f7cf3cb41b4525d6394dc98a714eb8f7f/jiter-0.15.0-cp313-cp313-win32.whl", hash = "sha256:c77496cb10bd7549690fbbab3e5ec05857b83e49276f4a9423a766ddd2afcd4c", size = 205845, upload-time = "2026-05-19T10:08:18.401Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/5c20d9ad6f02c493e4023e5d2d09e1c1f15fe2753c9102c544aff068a88e/jiter-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b15741f501469009ae0ae90b7147958a664a7dede40aa7ff174a8a4645f546d0", size = 196842, upload-time = "2026-05-19T10:08:20.131Z" }, + { url = "https://files.pythonhosted.org/packages/6b/11/1eb400ef248e8c925fd883fbe325daf5e42cd1b0d308539dd332bd4f7ffc/jiter-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d6a60072b44c3c2b797a7ddcbcbbf2b34ea3cfd4721580fbfd2a09d9d9b84ba", size = 192212, upload-time = "2026-05-19T10:08:21.807Z" }, + { url = "https://files.pythonhosted.org/packages/8a/60/2fd8d7c79da8acf9b7b277c7616847773779356b92acfc9bb158452174da/jiter-0.15.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ef1fd24d9413f6209e00d3d5a453e67acfe004a25cc6c8e8484faed4311ab9e8", size = 315065, upload-time = "2026-05-19T10:08:23.218Z" }, + { url = "https://files.pythonhosted.org/packages/46/f4/008fb7d65e8ac2abf00811651a661e025c4ba80bbc6f378450384ddd3aed/jiter-0.15.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:144f8e72cb53dab146347b91cceac01f5481237f2b93b4a339a1ee8f8878b67c", size = 339444, upload-time = "2026-05-19T10:08:24.701Z" }, + { url = "https://files.pythonhosted.org/packages/00/55/90b0c7b9c6896c0f2a591dd36d36b71d22e09674bfef178fa03ba3f81499/jiter-0.15.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553fcac2ef2cb990877f9fc0833b8b629a3e6a5670b6b5fd58219b41a653ddc4", size = 347779, upload-time = "2026-05-19T10:08:26.408Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/69666cec5000fd57734c118437394516c749ae8dbeea9fb66d6fef9c4775/jiter-0.15.0-cp313-cp313t-win_amd64.whl", hash = "sha256:774f93f65031856bf14ad9f59bdcab8b8cad501e5ceabd51ba3525f76937a25b", size = 200395, upload-time = "2026-05-19T10:08:28.055Z" }, + { url = "https://files.pythonhosted.org/packages/39/04/a6aa62cd27e8149b0d28df5561f10f6cceaf7935a9ccf3f1c5a05f9a0cd8/jiter-0.15.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f1e1754960f38ec40613a07e5e372df67acb3b890fb383b6fb3de3e49ddbf3c7", size = 190516, upload-time = "2026-05-19T10:08:29.35Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d2/079f350ebf7859d081de30aa890f9e3be68516f754f3ba32366ffff4dcee/jiter-0.15.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:ac0d9ddea4350974be7a221fc25895f251a8fee748c889bdced2141c0fec1a49", size = 308884, upload-time = "2026-05-19T10:08:31.667Z" }, + { url = "https://files.pythonhosted.org/packages/04/4e/a2c30a7f69b48c03b20935d647479106fe932f6e63f75faf53937197e05d/jiter-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:01a8222cf05ab1128e239421156c207949808acaaea2bdfd33130ae666786e86", size = 310028, upload-time = "2026-05-19T10:08:33.304Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/2e7cdfd3cf8ca967be38c48f5cf474d79f089efaf559a40f15984a77ae69/jiter-0.15.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:182226cbc930c9fab81bc2e41a4da672f89539906dadb05e75670ac07b94f71f", size = 337485, upload-time = "2026-05-19T10:08:35.259Z" }, + { url = "https://files.pythonhosted.org/packages/9b/11/15a1aa28b120b8ee5b4f1fb894c125046225f09847738bd64233d3b84883/jiter-0.15.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:71683c38c825452999b5717fcae07ea708e8c93003e808be4319c1b02e3d176e", size = 364223, upload-time = "2026-05-19T10:08:36.694Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/f442e8af5f3d0dcf47b39e83a0efd9ee45ea946aa6d04625dc3181eae3b6/jiter-0.15.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f2218e6a9e5c18bc10fe6d41ac189c442c88eacf11bad9f28ef95a9bef00e6", size = 456387, upload-time = "2026-05-19T10:08:38.143Z" }, + { url = "https://files.pythonhosted.org/packages/da/f4/37f2d2c9f64f49af7da652ed7532bb5a2372e588e6927c3fdd76f911db65/jiter-0.15.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5157de9f76eb4bc5ea74a1219366a25f945ad305641d74e04f59c54087091aa9", size = 374461, upload-time = "2026-05-19T10:08:39.869Z" }, + { url = "https://files.pythonhosted.org/packages/60/28/edcfbbbf0cb15436f36664a8908a0df47ab9006298d4cd937dc08ea932d6/jiter-0.15.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c5db5527c221249a876160663ab891ace358c17f7b9c93ec1478b7f0550e5c", size = 345924, upload-time = "2026-05-19T10:08:41.668Z" }, + { url = "https://files.pythonhosted.org/packages/47/13/89fba6398dab7f202b7278c4b4aac122399d2c0183971c4a57a3b7088df5/jiter-0.15.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:3e4540b8e74e4268811ac05db226a6a128ff572e7e0ce3f1163b693cadb184cd", size = 352283, upload-time = "2026-05-19T10:08:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/1b/da/0f6af8cef2c565a1ab44d970f268c43ccaa72707386ea6388e6fe2b6cd26/jiter-0.15.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62ebd14e47e9aed9df4472afcb2663668ce4d74891cd54f86bf6e44029d6dc89", size = 389985, upload-time = "2026-05-19T10:08:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ec/b9cb7d6d29e24ee14910266157d2a279d7a8f60ee0df7fa840882976ba64/jiter-0.15.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0be6f5ad41a809f303f416d17cec92a7a725902fb9b4f3de3d19362ac0ef8554", size = 517695, upload-time = "2026-05-19T10:08:46.486Z" }, + { url = "https://files.pythonhosted.org/packages/64/5e/6d1bda880723aae0ad86b4b763f044362448efe31e3e819635d41cb03451/jiter-0.15.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:813dfbb17d65328bf86e5f0905dd277ba2265d3ca20556e86c0c7035b7182e5a", size = 548868, upload-time = "2026-05-19T10:08:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/0c/72/7de501cf38dcacaf35098796f3a50e0f2e338baba18a58946c618544b809/jiter-0.15.0-cp314-cp314-win32.whl", hash = "sha256:50e51156192722a9c58db112837d3f8ef96fb3c5ecc14e95f409134b08b158ec", size = 206380, upload-time = "2026-05-19T10:08:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/1e/a9/e19addf4b0c1bdce52c6da12351e6bc42c340c45e7c09e2158e46d293ccc/jiter-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:30ce1a5d16b5641dc935d50ef775af6a0871e3d14ab05d6fc54dff371b78e558", size = 197687, upload-time = "2026-05-19T10:08:51.088Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c9/776b1db01db25fc6c1d58d1979a37b0a9fe787e5f5b1d062d2eaacb77923/jiter-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:510c8b3c17a0ed9ac69850c0438dada3c9b82d9c4d589fcb62002a5a9cf3a866", size = 192571, upload-time = "2026-05-19T10:08:52.451Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f6/45bb4670bacf300fd2c7abadbfb3af376e5f1b6ae75fd9bc069891d15870/jiter-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7553333dd0930c104a5a0db8df72bf7219fe663d731383b576bb6ed6351c984d", size = 317151, upload-time = "2026-05-19T10:08:53.867Z" }, + { url = "https://files.pythonhosted.org/packages/d7/68/ed635ad5acd7b73e454283083bbb7c8205ad10e88b0d9d7d793b09fe8226/jiter-0.15.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2143ab06181d2b029eedcb6af3cebe95f11bbac62441781860f98ee9330a6a6", size = 341243, upload-time = "2026-05-19T10:08:55.383Z" }, + { url = "https://files.pythonhosted.org/packages/5d/db/3ff4176b817b8ea33879e71e13d8bc2b0d481a7ed3fe9e080f333d415c16/jiter-0.15.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eac374c5c975709b69c10f09afd199df74150172156ad10c8d4fd785b7da995", size = 363629, upload-time = "2026-05-19T10:08:56.928Z" }, + { url = "https://files.pythonhosted.org/packages/ab/24/5f8270e0ba9c883582f96f722f8a0b58015c7ce1f8c6d4571cf394e99b6b/jiter-0.15.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3b3b775e33d3bfaec9899edc526ae97b0da0bf9d071a46124ba419149a414f8", size = 456198, upload-time = "2026-05-19T10:08:58.618Z" }, + { url = "https://files.pythonhosted.org/packages/45/5b/76fc02b0b5c54c3d18c60653156e2f76fde1816f9b4722db68d6ee2c897e/jiter-0.15.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3071db3346334beae1360b46da4606da57bf3528c167b3c38533afaf9f2c5", size = 373710, upload-time = "2026-05-19T10:09:00.151Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/4310821b0ea9277994d3e1f49fc6a4b34e4800caebacb2c0af81da59a454/jiter-0.15.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6694a173ecabc12eb60efbc0b474464ead1951ff65cd8b1e72100715c64512b", size = 349901, upload-time = "2026-05-19T10:09:01.621Z" }, + { url = "https://files.pythonhosted.org/packages/93/fe/67648c35b3594fba8854ac64cc8a826d8bcd18324bbdb53d77697c60b6ef/jiter-0.15.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:a254e10b593624d230c365b6d616b22ca0ad65e63a16e6631c2b3466022e6ba8", size = 352438, upload-time = "2026-05-19T10:09:03.216Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/0a1879d07ad6b3e025a2750027363452ced93c2d16d1c9d4b153ffd51c91/jiter-0.15.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8d2955167274e15d79a7a020afdd9b39c990eb80b2d89fca695d92dcfdd38ec", size = 388152, upload-time = "2026-05-19T10:09:04.741Z" }, + { url = "https://files.pythonhosted.org/packages/c1/78/46c6f6b56ba85c90021f4afd72ed42f691f8f84daacb5fe27277070e3858/jiter-0.15.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:acf4ee4d1fc55917239fe72972fb292dd773055d05eb040d36f4326e02cc2c0e", size = 517707, upload-time = "2026-05-19T10:09:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/ca/cb/720662d4c88fcad606e826fef5424365527ba43ce4868a479aed8f8c507e/jiter-0.15.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:e7196e56f1cd69af1dbb07dff02dcfb260a50b45a82d409d92a06fedb32473b5", size = 548241, upload-time = "2026-05-19T10:09:08.093Z" }, + { url = "https://files.pythonhosted.org/packages/60/e3/935b8034fd143f21125c87d51404a9e0e1449186a494405721ff5d1d695e/jiter-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:7f6163c0f10b055245f814dcc59f4818da60dfe72f3e72ab89fc24b6bd5e9c52", size = 207950, upload-time = "2026-05-19T10:09:09.616Z" }, + { url = "https://files.pythonhosted.org/packages/93/59/984fd9ece895953dad3e0880a650e766f5a2da2c5514f0eafdaaabbeb5f9/jiter-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:980c256edb05b78a111b99c4de3b1d32e31634b867fd1fc2cf726e7b7bba9854", size = 200055, upload-time = "2026-05-19T10:09:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a4/cf8d779feb133a27a2e3bc833bccb9e13aa332cdf820497ebf72c10ce8c3/jiter-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:66b1880df2d01e206e8339769d1c7c1753bcb653efd6289e203f6f24ebada0c0", size = 191244, upload-time = "2026-05-19T10:09:12.74Z" }, +] + +[[package]] +name = "librt" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, + { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, + { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, + { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" }, + { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" }, + { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" }, + { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" }, + { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" }, + { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" }, + { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" }, + { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" }, + { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" }, + { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" }, + { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" }, + { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" }, + { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" }, + { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" }, + { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" }, + { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" }, ] [[package]] @@ -871,14 +1009,14 @@ wheels = [ [[package]] name = "markdown-it-py" -version = "4.0.0" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, ] [[package]] @@ -944,7 +1082,7 @@ wheels = [ [[package]] name = "meijiaka-ai-api" -version = "1.8.2" +version = "1.9.1" source = { virtual = "." } dependencies = [ { name = "aiohttp" }, @@ -959,6 +1097,7 @@ dependencies = [ { name = "passlib", extra = ["bcrypt"] }, { name = "pillow" }, { name = "psycopg2-binary" }, + { name = "pyasn1" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pyjwt" }, @@ -987,16 +1126,16 @@ dev = [ [package.metadata] requires-dist = [ - { name = "aiohttp", specifier = ">=3.13.4" }, + { name = "aiohttp", specifier = ">=3.14.0" }, { name = "alembic", specifier = "~=1.14.0" }, { name = "asyncpg", specifier = "~=0.30.0" }, { name = "bandit", extras = ["toml"], marker = "extra == 'dev'", specifier = "~=1.8.0" }, { name = "bcrypt", specifier = "~=4.2.0" }, - { name = "black", marker = "extra == 'dev'", specifier = "~=24.10.0" }, - { name = "fastapi", specifier = ">=0.136.1" }, - { name = "httpx", specifier = "~=0.28.0" }, + { name = "black", marker = "extra == 'dev'", specifier = ">=26.3.1" }, + { name = "fastapi", specifier = ">=0.115.8" }, + { name = "httpx", specifier = ">=0.28.0" }, { name = "mutagen", specifier = "~=1.47.0" }, - { name = "mypy", marker = "extra == 'dev'", specifier = "~=1.14.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.14.0" }, { name = "openai", specifier = "~=1.58.0" }, { name = "orjson", specifier = ">=3.11.0" }, { name = "passlib", extras = ["bcrypt"], specifier = "~=1.7.4" }, @@ -1004,17 +1143,18 @@ requires-dist = [ { name = "pip-audit", marker = "extra == 'dev'", specifier = "~=2.7.0" }, { name = "pre-commit", marker = "extra == 'dev'", specifier = "~=4.0.0" }, { name = "psycopg2-binary", specifier = "~=2.9.10" }, + { name = "pyasn1", specifier = ">=0.6.3" }, { name = "pydantic", specifier = "~=2.9.0" }, { name = "pydantic-settings", specifier = "~=2.6.0" }, - { name = "pyjwt", specifier = "~=2.10.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = "~=8.3.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = "~=0.24.0" }, - { name = "pytest-cov", marker = "extra == 'dev'", specifier = "~=6.0.0" }, - { name = "python-multipart", specifier = "~=0.0.20" }, + { name = "pyjwt", specifier = ">=2.13.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.3" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24.0" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.0.0" }, + { name = "python-multipart", specifier = ">=0.0.27" }, { name = "pyyaml", specifier = "~=6.0.2" }, { name = "qiniu", specifier = "~=7.13.0" }, { name = "redis", specifier = "~=5.2.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = "~=0.8.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.8.0" }, { name = "sqlalchemy", extras = ["asyncio"], specifier = "~=2.0.36" }, { name = "tenacity", specifier = "~=9.0.0" }, { name = "uvicorn", extras = ["standard"], specifier = "~=0.32.0" }, @@ -1024,37 +1164,43 @@ provides-extras = ["dev"] [[package]] name = "msgpack" -version = "1.1.2" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/92/23/6139781ca7aadf656fa8e384fa84693ffb13f299e6931b6526427fe5e297/msgpack-1.2.0.tar.gz", hash = "sha256:8e17af38197bf58e7e819041678f6178f4491493f5b8c8580414f40f7c2c3c41", size = 183017, upload-time = "2026-06-11T04:16:10.775Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, - { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, - { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, - { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, - { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, - { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, - { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, - { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, - { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, - { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, - { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, - { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, - { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, - { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, - { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, + { url = "https://files.pythonhosted.org/packages/7d/26/2902c6946ab5c8fe1e46e40842dfc32b8824464ad5cd4725364fd83f7a58/msgpack-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3a1d30df1f302f2b7a7404afbac2ab76d510036c34cf34dffb01f704a7288e45", size = 82621, upload-time = "2026-06-11T04:15:23.844Z" }, + { url = "https://files.pythonhosted.org/packages/c9/59/7e6b812629d2f919e586041bffc130e1af32079f71bb20699eed54ed6d92/msgpack-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:581e317112260d8ca488d490cad9290a5682276f309c41c7de237a85ed8799c8", size = 81866, upload-time = "2026-06-11T04:15:25.032Z" }, + { url = "https://files.pythonhosted.org/packages/31/13/8c291196e60aafdbae38f482205d79432297749ac5d412fe638154fb6f1d/msgpack-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6827d12eacc16873eba62408a1b7bbe8ecfb4a8f7ed78a631ae9bae6ad43cf2", size = 405618, upload-time = "2026-06-11T04:15:26.235Z" }, + { url = "https://files.pythonhosted.org/packages/fb/63/68f5d0ea81e167db5f59ddb94dc6f837667062113feff1c73fabf8907061/msgpack-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a186027e4279efa4c8bf06ce30605498d7d0d3af0fba0b9799dce85a3fd4a93c", size = 416468, upload-time = "2026-06-11T04:15:27.732Z" }, + { url = "https://files.pythonhosted.org/packages/73/58/567dddf5c5a2790f673bcd7d80c83466d68e5ee9a9674ebca3db8101c0c8/msgpack-1.2.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a96142c14a11cf1a509e8b9aaf72858a3b742b7613e095ce646913e88ce7bd99", size = 374464, upload-time = "2026-06-11T04:15:29.286Z" }, + { url = "https://files.pythonhosted.org/packages/0d/30/0c2342fc9092e4498045f5f60bca6ccbe4f4d87789778c2300e6fd6efe82/msgpack-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50c220579b68a6085b95408b2eaa486b259520f55d8e363ddc9b5d7ba5a6ac6d", size = 395879, upload-time = "2026-06-11T04:15:30.973Z" }, + { url = "https://files.pythonhosted.org/packages/b9/11/9565b29b58ce3c33e177b490478b7aaeb8f726ecaaeda26d815893c1db5a/msgpack-1.2.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4dcb9d12ab100ecacdfaaf37a3d72fe8392eacc7054afc1916b12d1b747c8446", size = 371749, upload-time = "2026-06-11T04:15:32.418Z" }, + { url = "https://files.pythonhosted.org/packages/f2/da/7bade19d60b73e2ef73fb76aaf4504c112a70cb760951b7202a0c64b5111/msgpack-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a804727188ab0ebb237fadb303b743f04925a69d8c3247292d1e33e679767c15", size = 410416, upload-time = "2026-06-11T04:15:34.053Z" }, + { url = "https://files.pythonhosted.org/packages/6d/14/c0c619571c02432208a5977a8dbdd3fc65fe1369f8226ca4b6d08cca87d8/msgpack-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1a1ac6ae1fe23298f79380e7b144c8a454e5d05616b0096584f353ba2d750114", size = 64357, upload-time = "2026-06-11T04:15:35.535Z" }, + { url = "https://files.pythonhosted.org/packages/50/a5/de06718460909aa965737fec4cfe8a15dedc6544a8c55feeb6956fa0d6e3/msgpack-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c3c80949d79578f9dc85fd9fb91edfe6694e8a729cd5744634d59d8455fdde3", size = 71057, upload-time = "2026-06-11T04:15:36.83Z" }, + { url = "https://files.pythonhosted.org/packages/c7/52/73446b0141c94a856e22b787c56709c0815fc34f185326577e15b26d8cfe/msgpack-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fcf8f76fa587c2395fd0057c7232dbf071241f9ad280b235adb7ab585289989e", size = 64490, upload-time = "2026-06-11T04:15:38.001Z" }, + { url = "https://files.pythonhosted.org/packages/35/3d/a7e3cdafa8c0cf36c81e2fa848ec4d30cf089459af45b390ad03f9ce6f49/msgpack-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f854fa1a8b55d75d82ef9a905d9cdbeffdf7897c088f6020bd221867da5e56a5", size = 83032, upload-time = "2026-06-11T04:15:39.38Z" }, + { url = "https://files.pythonhosted.org/packages/ca/aa/53ddfba0e347cc4b484e95f629c5850b9e800ca8390c91ffc604407acf87/msgpack-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e90df581f80f53b372d5d9d9349078d729851a3a0d0bd74f53ccb598d01e45b8", size = 82600, upload-time = "2026-06-11T04:15:40.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/fd/e64c2c776e6dbad0af3c963fe0c0dd1ee1ba09efac478b233ab1db41868f/msgpack-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b276ed50d8ac75d1f134a433ae79af8557d0fa25ee5b4737da533dfc2ce382e8", size = 404342, upload-time = "2026-06-11T04:15:41.87Z" }, + { url = "https://files.pythonhosted.org/packages/1b/60/fb9a08e6ccba882dfd370a5837fe3a07572938fdfe954f0f17fdf3e574b9/msgpack-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:544d972459c92aa32e63b800d07c2d9cf2734a3be29cee3a0b478a622850e9f5", size = 412351, upload-time = "2026-06-11T04:15:43.253Z" }, + { url = "https://files.pythonhosted.org/packages/37/4d/df5c575c274fedc68ac9c6c61d045161899efad2afcdc25138efa7edde69/msgpack-1.2.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a070147cc2cf6b8a891734e0f5c8fe8f70ed8739ab30ba140b058005a6e86af4", size = 373331, upload-time = "2026-06-11T04:15:44.754Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a4/c8b98f8191e985ed2003d87664ce3c95cca41db5d0cf6bf4f54327d32ec8/msgpack-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7685e23b0f51745a751629c31713fbefdef8896b31b2bb38299dfa4ae6c0740c", size = 394654, upload-time = "2026-06-11T04:15:46.423Z" }, + { url = "https://files.pythonhosted.org/packages/d4/49/76f036720a602ea24428cfec5ec806f2487c0380b1bff0a2aa3094e15f87/msgpack-1.2.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b9204daeee8d91a7ae5acf2d2a8e3983be9a3025f38aa21bfaefbd7eea84a7dc", size = 370624, upload-time = "2026-06-11T04:15:48.062Z" }, + { url = "https://files.pythonhosted.org/packages/9f/38/40af3d29232833705a43b0fce0d07425cc280a7b92ab2b29932425b40df4/msgpack-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bfc057248609742ebbabf6bcd27fea4fd99c4980584e613c168c9b002318298f", size = 408038, upload-time = "2026-06-11T04:15:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/30/b2/f140ca450524dff4d8d0eb81eb9ed75f8f3e0b1f12e49c5b01617cfa0b1c/msgpack-1.2.0-cp314-cp314-win32.whl", hash = "sha256:a3faa7edf2388337ae849239878e92f0298b4dab4488e4f1834062f9d0c410c9", size = 65823, upload-time = "2026-06-11T04:15:51.062Z" }, + { url = "https://files.pythonhosted.org/packages/4d/13/6517bf966b841c7675ded30701a068ce141f3e698a27aaa35c702d8e078b/msgpack-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:1a3effc392a57744e4681e55d05f97d5ee7b598747d718340a9b4b8a970c40e1", size = 72484, upload-time = "2026-06-11T04:15:52.289Z" }, + { url = "https://files.pythonhosted.org/packages/45/8c/1d948420fdaa24de4efdb8012a6a5bebe09c82ee002b8c2ca745e9917f1f/msgpack-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:56a318f7df6bec7b40928d6b0519961f20a510d8baabf6baa393a70444588f0a", size = 66657, upload-time = "2026-06-11T04:15:53.583Z" }, + { url = "https://files.pythonhosted.org/packages/39/16/1674faa1b7bddc19e79b465fd8e88e2cf4e3f7cae90723740701e8541068/msgpack-1.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:afa4a65ab2097795e771a74a3a81ea49534aaeba874eaf426a3332268e045ae6", size = 86093, upload-time = "2026-06-11T04:15:54.98Z" }, + { url = "https://files.pythonhosted.org/packages/dd/24/f241bcfdd9e96b2246289357c5a5e5a496189fd41c5844bee802c116aac7/msgpack-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:409550770632bb28daa70a11d0ed5763f7db38f40b06f7db9f11dd2794d01102", size = 86372, upload-time = "2026-06-11T04:15:56.381Z" }, + { url = "https://files.pythonhosted.org/packages/94/c9/57f8ab98a1b21808c27b6dd6029053e0a796ffbb9b371e460dbe997011a9/msgpack-1.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf47e3cd11ce044965a9736a322afdd390b31ed602d1c1b10211d1a841f1d587", size = 428207, upload-time = "2026-06-11T04:15:57.739Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/4fd4aa739f131ded751ca7167c8ee87d2aab32506ebbeea893b60b51d343/msgpack-1.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:204bc9f5d6e59c1718c0a4a84fc8ff71b5b4562faac257c1a68bca611ecf9b72", size = 426082, upload-time = "2026-06-11T04:15:59.356Z" }, + { url = "https://files.pythonhosted.org/packages/f9/00/db88e9a08fcd6513decaad06cbd5c168142bc3e662fb2f1aca3a563b7aa1/msgpack-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:610154307b27267266368bc1d1c7bb8aeb71da7be9356d403cb2442d9e6399f5", size = 378355, upload-time = "2026-06-11T04:16:00.916Z" }, + { url = "https://files.pythonhosted.org/packages/54/84/eee4dd703d7a600cf46159d621c070b0b9468cf3dbade4ea8272bf5232a4/msgpack-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6799f157bb63e79f11e2e590cfdb28423fc18dd60c270c3914b5b4586ae36f7e", size = 410848, upload-time = "2026-06-11T04:16:02.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/0a/195e2c549fd4631eb7f157d016ff15a10c4c1cf82b6d0a9b1edaef5174b1/msgpack-1.2.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:72bd844902cf0a5ac3af2ef742f253cd0b1e5bcd184f49b4fb9a6a1f7bf305e8", size = 376152, upload-time = "2026-06-11T04:16:04.041Z" }, + { url = "https://files.pythonhosted.org/packages/45/9b/bdd143fa79baec411dc658f5686fed680a18b36fcea5fccb6af1b8c7d832/msgpack-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3c0bd450f78d0d81722c80da6cdbf674a856967870a9db2f6c4debc4d8b3c67c", size = 417061, upload-time = "2026-06-11T04:16:05.63Z" }, + { url = "https://files.pythonhosted.org/packages/2d/ce/011ffcd8b919f55196ec53f12ae162e21c879d95afba226894314ff62c07/msgpack-1.2.0-cp314-cp314t-win32.whl", hash = "sha256:378caf74c4c718dfc17590ce68a6d710ed398ff6fcf08237de23b77755730b55", size = 70782, upload-time = "2026-06-11T04:16:07.105Z" }, + { url = "https://files.pythonhosted.org/packages/57/a8/9b8791ca96b1be6b9f659c718271e2cb7f99f73f58aad2dd0b30f750f6c0/msgpack-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:553b42598165c4dd3235994fd6e4b0dfb1ce5f3fd33d94ba9609442643015f38", size = 77899, upload-time = "2026-06-11T04:16:08.353Z" }, + { url = "https://files.pythonhosted.org/packages/5b/04/3fa2dffb87bf598696b86bde7cd642d0a7590520c3fa24cd19611dfebeb7/msgpack-1.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2825bb1da548d214ab8a810906b7dd69a10f3838b615a2cc46e5172d3cb44f6e", size = 71004, upload-time = "2026-06-11T04:16:09.556Z" }, ] [[package]] @@ -1149,21 +1295,39 @@ wheels = [ [[package]] name = "mypy" -version = "1.14.1" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "ast-serialize" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, + { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051, upload-time = "2024-12-30T16:39:07.335Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097, upload-time = "2024-12-30T16:37:25.144Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728, upload-time = "2024-12-30T16:38:08.634Z" }, - { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965, upload-time = "2024-12-30T16:38:12.132Z" }, - { url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660, upload-time = "2024-12-30T16:38:17.342Z" }, - { url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198, upload-time = "2024-12-30T16:38:32.839Z" }, - { url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276, upload-time = "2024-12-30T16:38:20.828Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905, upload-time = "2024-12-30T16:38:42.021Z" }, + { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" }, + { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" }, + { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" }, + { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" }, + { url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" }, + { url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" }, + { url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" }, + { url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" }, + { url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" }, + { url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" }, ] [[package]] @@ -1205,40 +1369,40 @@ wheels = [ [[package]] name = "orjson" -version = "3.11.8" +version = "3.11.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e", size = 5603832, upload-time = "2026-03-31T16:16:27.878Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/7f/95fba509bb2305fab0073558f1e8c3a2ec4b2afe58ed9fcb7d3b8beafe94/orjson-3.11.8-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3f23426851d98478c8970da5991f84784a76682213cd50eb73a1da56b95239dc", size = 229180, upload-time = "2026-03-31T16:15:36.426Z" }, - { url = "https://files.pythonhosted.org/packages/f6/9d/b237215c743ca073697d759b5503abd2cb8a0d7b9c9e21f524bcf176ab66/orjson-3.11.8-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ebaed4cef74a045b83e23537b52ef19a367c7e3f536751e355a2a394f8648559", size = 128754, upload-time = "2026-03-31T16:15:38.049Z" }, - { url = "https://files.pythonhosted.org/packages/42/3d/27d65b6d11e63f133781425f132807aef793ed25075fec686fc8e46dd528/orjson-3.11.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97c8f5d3b62380b70c36ffacb2a356b7c6becec86099b177f73851ba095ef623", size = 131877, upload-time = "2026-03-31T16:15:39.484Z" }, - { url = "https://files.pythonhosted.org/packages/dd/cc/faee30cd8f00421999e40ef0eba7332e3a625ce91a58200a2f52c7fef235/orjson-3.11.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:436c4922968a619fb7fef1ccd4b8b3a76c13b67d607073914d675026e911a65c", size = 130361, upload-time = "2026-03-31T16:15:41.274Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bb/a6c55896197f97b6d4b4e7c7fd77e7235517c34f5d6ad5aadd43c54c6d7c/orjson-3.11.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ab359aff0436d80bfe8a23b46b5fea69f1e18aaf1760a709b4787f1318b317f", size = 135521, upload-time = "2026-03-31T16:15:42.758Z" }, - { url = "https://files.pythonhosted.org/packages/9c/7c/ca3a3525aa32ff636ebb1778e77e3587b016ab2edb1b618b36ba96f8f2c0/orjson-3.11.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f89b6d0b3a8d81e1929d3ab3d92bbc225688bd80a770c49432543928fe09ac55", size = 146862, upload-time = "2026-03-31T16:15:44.341Z" }, - { url = "https://files.pythonhosted.org/packages/3c/0c/18a9d7f18b5edd37344d1fd5be17e94dc652c67826ab749c6e5948a78112/orjson-3.11.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c009e7a2ca9ad0ed1376ce20dd692146a5d9fe4310848904b6b4fee5c5c137", size = 132847, upload-time = "2026-03-31T16:15:46.368Z" }, - { url = "https://files.pythonhosted.org/packages/23/91/7e722f352ad67ca573cee44de2a58fb810d0f4eb4e33276c6a557979fd8a/orjson-3.11.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b895b781b3e395c067129d8551655642dfe9437273211d5404e87ac752b53", size = 133637, upload-time = "2026-03-31T16:15:48.123Z" }, - { url = "https://files.pythonhosted.org/packages/af/04/32845ce13ac5bd1046ddb02ac9432ba856cc35f6d74dde95864fe0ad5523/orjson-3.11.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:88006eda83858a9fdf73985ce3804e885c2befb2f506c9a3723cdeb5a2880e3e", size = 141906, upload-time = "2026-03-31T16:15:49.626Z" }, - { url = "https://files.pythonhosted.org/packages/02/5e/c551387ddf2d7106d9039369862245c85738b828844d13b99ccb8d61fd06/orjson-3.11.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:55120759e61309af7fcf9e961c6f6af3dde5921cdb3ee863ef63fd9db126cae6", size = 423722, upload-time = "2026-03-31T16:15:51.176Z" }, - { url = "https://files.pythonhosted.org/packages/00/a3/ecfe62434096f8a794d4976728cb59bcfc4a643977f21c2040545d37eb4c/orjson-3.11.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98bdc6cb889d19bed01de46e67574a2eab61f5cc6b768ed50e8ac68e9d6ffab6", size = 147801, upload-time = "2026-03-31T16:15:52.939Z" }, - { url = "https://files.pythonhosted.org/packages/18/6d/0dce10b9f6643fdc59d99333871a38fa5a769d8e2fc34a18e5d2bfdee900/orjson-3.11.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:708c95f925a43ab9f34625e45dcdadf09ec8a6e7b664a938f2f8d5650f6c090b", size = 136460, upload-time = "2026-03-31T16:15:54.431Z" }, - { url = "https://files.pythonhosted.org/packages/01/d6/6dde4f31842d87099238f1f07b459d24edc1a774d20687187443ab044191/orjson-3.11.8-cp313-cp313-win32.whl", hash = "sha256:01c4e5a6695dc09098f2e6468a251bc4671c50922d4d745aff1a0a33a0cf5b8d", size = 131956, upload-time = "2026-03-31T16:15:56.081Z" }, - { url = "https://files.pythonhosted.org/packages/c1/f9/4e494a56e013db957fb77186b818b916d4695b8fa2aa612364974160e91b/orjson-3.11.8-cp313-cp313-win_amd64.whl", hash = "sha256:c154a35dd1330707450bb4d4e7dd1f17fa6f42267a40c1e8a1daa5e13719b4b8", size = 127410, upload-time = "2026-03-31T16:15:57.54Z" }, - { url = "https://files.pythonhosted.org/packages/57/7f/803203d00d6edb6e9e7eef421d4e1adbb5ea973e40b3533f3cfd9aeb374e/orjson-3.11.8-cp313-cp313-win_arm64.whl", hash = "sha256:4861bde57f4d253ab041e374f44023460e60e71efaa121f3c5f0ed457c3a701e", size = 127338, upload-time = "2026-03-31T16:15:59.106Z" }, - { url = "https://files.pythonhosted.org/packages/6d/35/b01910c3d6b85dc882442afe5060cbf719c7d1fc85749294beda23d17873/orjson-3.11.8-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ec795530a73c269a55130498842aaa762e4a939f6ce481a7e986eeaa790e9da4", size = 229171, upload-time = "2026-03-31T16:16:00.651Z" }, - { url = "https://files.pythonhosted.org/packages/c2/56/c9ec97bd11240abef39b9e5d99a15462809c45f677420fd148a6c5e6295e/orjson-3.11.8-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c492a0e011c0f9066e9ceaa896fbc5b068c54d365fea5f3444b697ee01bc8625", size = 128746, upload-time = "2026-03-31T16:16:02.673Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e4/66d4f30a90de45e2f0cbd9623588e8ae71eef7679dbe2ae954ed6d66a41f/orjson-3.11.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:883206d55b1bd5f5679ad5e6ddd3d1a5e3cac5190482927fdb8c78fb699193b5", size = 131867, upload-time = "2026-03-31T16:16:04.342Z" }, - { url = "https://files.pythonhosted.org/packages/19/30/2a645fc9286b928675e43fa2a3a16fb7b6764aa78cc719dc82141e00f30b/orjson-3.11.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5774c1fdcc98b2259800b683b19599c133baeb11d60033e2095fd9d4667b82db", size = 124664, upload-time = "2026-03-31T16:16:05.837Z" }, - { url = "https://files.pythonhosted.org/packages/db/44/77b9a86d84a28d52ba3316d77737f6514e17118119ade3f91b639e859029/orjson-3.11.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7381c83dd3d4a6347e6635950aa448f54e7b8406a27c7ecb4a37e9f1ae08b", size = 129701, upload-time = "2026-03-31T16:16:07.407Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ea/eff3d9bfe47e9bc6969c9181c58d9f71237f923f9c86a2d2f490cd898c82/orjson-3.11.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14439063aebcb92401c11afc68ee4e407258d2752e62d748b6942dad20d2a70d", size = 141202, upload-time = "2026-03-31T16:16:09.48Z" }, - { url = "https://files.pythonhosted.org/packages/52/c8/90d4b4c60c84d62068d0cf9e4d8f0a4e05e76971d133ac0c60d818d4db20/orjson-3.11.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa72e71977bff96567b0f500fc5bfd2fdf915f34052c782a4c6ebbdaa97aa858", size = 127194, upload-time = "2026-03-31T16:16:11.02Z" }, - { url = "https://files.pythonhosted.org/packages/8d/c7/ea9e08d1f0ba981adffb629811148b44774d935171e7b3d780ae43c4c254/orjson-3.11.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7679bc2f01bb0d219758f1a5f87bb7c8a81c0a186824a393b366876b4948e14f", size = 133639, upload-time = "2026-03-31T16:16:13.434Z" }, - { url = "https://files.pythonhosted.org/packages/6c/8c/ddbbfd6ba59453c8fc7fe1d0e5983895864e264c37481b2a791db635f046/orjson-3.11.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14f7b8fcb35ef403b42fa5ecfa4ed032332a91f3dc7368fbce4184d59e1eae0d", size = 141914, upload-time = "2026-03-31T16:16:14.955Z" }, - { url = "https://files.pythonhosted.org/packages/4e/31/dbfbefec9df060d34ef4962cd0afcb6fa7a9ec65884cb78f04a7859526c3/orjson-3.11.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c2bdf7b2facc80b5e34f48a2d557727d5c5c57a8a450de122ae81fa26a81c1bc", size = 423800, upload-time = "2026-03-31T16:16:16.594Z" }, - { url = "https://files.pythonhosted.org/packages/87/cf/f74e9ae9803d4ab46b163494adba636c6d7ea955af5cc23b8aaa94cfd528/orjson-3.11.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ccd7ba1b0605813a0715171d39ec4c314cb97a9c85893c2c5c0c3a3729df38bf", size = 147837, upload-time = "2026-03-31T16:16:18.585Z" }, - { url = "https://files.pythonhosted.org/packages/64/e6/9214f017b5db85e84e68602792f742e5dc5249e963503d1b356bee611e01/orjson-3.11.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdbc8c9c02463fef4d3c53a9ba3336d05496ec8e1f1c53326a1e4acc11f5c600", size = 136441, upload-time = "2026-03-31T16:16:20.151Z" }, - { url = "https://files.pythonhosted.org/packages/24/dd/3590348818f58f837a75fb969b04cdf187ae197e14d60b5e5a794a38b79d/orjson-3.11.8-cp314-cp314-win32.whl", hash = "sha256:0b57f67710a8cd459e4e54eb96d5f77f3624eba0c661ba19a525807e42eccade", size = 131983, upload-time = "2026-03-31T16:16:21.823Z" }, - { url = "https://files.pythonhosted.org/packages/3f/0f/b6cb692116e05d058f31ceee819c70f097fa9167c82f67fabe7516289abc/orjson-3.11.8-cp314-cp314-win_amd64.whl", hash = "sha256:735e2262363dcbe05c35e3a8869898022af78f89dde9e256924dc02e99fe69ca", size = 127396, upload-time = "2026-03-31T16:16:23.685Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d1/facb5b5051fabb0ef9d26c6544d87ef19a939a9a001198655d0d891062dd/orjson-3.11.8-cp314-cp314-win_arm64.whl", hash = "sha256:6ccdea2c213cf9f3d9490cbd5d427693c870753df41e6cb375bd79bcbafc8817", size = 127330, upload-time = "2026-03-31T16:16:25.496Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/93fcc25907235c344ae73122f8a4e01d2d393ef062b4af7d2e2487a32c37/orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021", size = 228458, upload-time = "2026-05-06T15:10:20.079Z" }, + { url = "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c", size = 128368, upload-time = "2026-05-06T15:10:21.549Z" }, + { url = "https://files.pythonhosted.org/packages/21/0f/c9ede0bf052f6b4051e64a7d4fa91b725cccf8321a6a786e86eb03519f00/orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81", size = 132070, upload-time = "2026-05-06T15:10:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/fd/26/d398e28048dc18205bbe812f2c88cb9b40313db2470778e25964796458fe/orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a", size = 127892, upload-time = "2026-05-06T15:10:24.714Z" }, + { url = "https://files.pythonhosted.org/packages/66/60/52b0054c4c700d5aa7fc5b7ca96917400d8f061307778578e67a10e25852/orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10", size = 135217, upload-time = "2026-05-06T15:10:26.084Z" }, + { url = "https://files.pythonhosted.org/packages/d5/97/1e3dc2b2a28b7b2528f403d2fc1d79ec5f39af3bc143ab65d3ec26426385/orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362", size = 145980, upload-time = "2026-05-06T15:10:28.062Z" }, + { url = "https://files.pythonhosted.org/packages/fc/39/31fbfe7850f2de32dee7e7e5c09f26d403ab01e440ac96001c6b01ad3c99/orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97", size = 132738, upload-time = "2026-05-06T15:10:29.727Z" }, + { url = "https://files.pythonhosted.org/packages/a1/08/dca0082dd2a194acb93e5457e73455388e2e2ca464a2672449a9ddbb679d/orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218", size = 134033, upload-time = "2026-05-06T15:10:31.152Z" }, + { url = "https://files.pythonhosted.org/packages/11/d4/5bdb0626801230139987385554c5d4c42255218ac906525bf4347f22cd95/orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9", size = 141492, upload-time = "2026-05-06T15:10:32.641Z" }, + { url = "https://files.pythonhosted.org/packages/fa/88/a21fb53b3ede6703aede6dce4710ed4111e5b201cfa6bbff5e544f9d47d7/orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677", size = 415087, upload-time = "2026-05-06T15:10:34.438Z" }, + { url = "https://files.pythonhosted.org/packages/3d/57/1b30daf70f0d8180e9a73cefbfbdd99e4bf19eb020466502b01fba7e0e50/orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4", size = 148031, upload-time = "2026-05-06T15:10:36.358Z" }, + { url = "https://files.pythonhosted.org/packages/04/83/45fbb6d962e260807f99441db9613cee868ceda4baceda59b3720a563f97/orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0", size = 136915, upload-time = "2026-05-06T15:10:38.013Z" }, + { url = "https://files.pythonhosted.org/packages/5f/cc/2d10025f9056d376e4127ec05a5808b218d46f035fdc08178a5411b34250/orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32", size = 131613, upload-time = "2026-05-06T15:10:39.569Z" }, + { url = "https://files.pythonhosted.org/packages/67/bd/2775ff28bfe883b9aa1ff348300542eb2ef1ee18d8ae0e3a49846817a865/orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979", size = 127086, upload-time = "2026-05-06T15:10:41.262Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/d26799e580939e32a7da9a39531bc9e58e15ca32ffaa6a8cb3e9bb0d22cd/orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254", size = 126696, upload-time = "2026-05-06T15:10:42.651Z" }, + { url = "https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e", size = 228465, upload-time = "2026-05-06T15:10:44.097Z" }, + { url = "https://files.pythonhosted.org/packages/64/62/3e0e0c14c957133bcd855395c62b55ed4e3b0af23ffea11b032cb1dcbdb1/orjson-3.11.9-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:f36b7f32c7c0db4a719f1fc5824db4a9c6f8bd1a354debb91faf26ebf3a4c71e", size = 128364, upload-time = "2026-05-06T15:10:45.839Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5a/07d8aa117211a8ed7630bda80c8c0b14d04e0f8dcf99bcf49656e4a710eb/orjson-3.11.9-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08f4d8ebb44925c794e535b2bebc507cebf32209df81de22ae285fb0d8d66de0", size = 132063, upload-time = "2026-05-06T15:10:47.267Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ec/4acaf21483e18aa945be74a474c74b434f284b549f275a0a39b9f98956e9/orjson-3.11.9-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6cc7923789694fd58f001cbcac7e47abc13af4d560ebbfcf3b41a8b1a0748124", size = 122356, upload-time = "2026-05-06T15:10:48.765Z" }, + { url = "https://files.pythonhosted.org/packages/13/d8/5f0555e7638801323b7a75850f92e7dfa891bc84fe27a1ba4449170d1200/orjson-3.11.9-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea5c46eb2d3af39e806b986f4b09d5c2706a1f5afde3cbf7544ce6616127173c", size = 129592, upload-time = "2026-05-06T15:10:50.13Z" }, + { url = "https://files.pythonhosted.org/packages/b6/30/ed9860412a3603ceb3c5955bfd72d28b9d0e7ba6ed81add14f83d7114236/orjson-3.11.9-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d89a2ed90731df3be64bab0aa44f78bff39fdc9d71c291f4a8023aa46425b7", size = 140491, upload-time = "2026-05-06T15:10:51.582Z" }, + { url = "https://files.pythonhosted.org/packages/d0/17/adc514dea7ac7c505527febf884934b815d34f0c7b8693c1a8b39c5c4a57/orjson-3.11.9-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25e4aed0312d292c09f61af25bba34e0b2c88546041472b09088c39a4d828af1", size = 127309, upload-time = "2026-05-06T15:10:53.329Z" }, + { url = "https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db", size = 134030, upload-time = "2026-05-06T15:10:54.988Z" }, + { url = "https://files.pythonhosted.org/packages/c1/7a/bc82a0bb25e9faaf92dc4d9ef002732efc09737706af83e346788641d4a7/orjson-3.11.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a028425d1b440c5d92a6be1e1a020739dfe67ea87d96c6dbe828c1b30041728b", size = 141482, upload-time = "2026-05-06T15:10:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/01/55/e69188b939f77d5d32a9833745ace31ea5ccae3ab613a1ec185d3cd2c4fb/orjson-3.11.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b192c6cf397e4455b11523c5cf2b18ed084c1bbd61b6c0926344d2129481972", size = 415178, upload-time = "2026-05-06T15:10:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1a/b8a5a7ac527e80b9cb11d51e3f6689b709279183264b9ec5c7bc680bb8b5/orjson-3.11.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea407d4ccf5891d667d045fecae97a7a1e5e87b3b97f97ae1803c2e741130be0", size = 148089, upload-time = "2026-05-06T15:11:00.441Z" }, + { url = "https://files.pythonhosted.org/packages/97/4e/00503f64204bf859b37213a63927028f30fb6268cd8677fb0a5ad48155e1/orjson-3.11.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f63aaf97afd9f6dec5b1a68e1b8da12bfccb4cb9a9a65c3e0b6c847849e7586", size = 136921, upload-time = "2026-05-06T15:11:02.176Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ba/a23b82a0a8d0ed7bed4e5f5035aae751cad4ff6a1e8d2ecd14d8860f5929/orjson-3.11.9-cp314-cp314-win32.whl", hash = "sha256:e30ab17845bb9fa54ccf67fa4f9f5282652d54faa6d17452f47d0f369d038673", size = 131638, upload-time = "2026-05-06T15:11:03.696Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/0c6798456bade745c75c452342dabacce5798196483e77e643be1f53877d/orjson-3.11.9-cp314-cp314-win_amd64.whl", hash = "sha256:32ef5f4283a3be81913947d19608eacb7c6608026851123790cd9cc8982af34b", size = 127078, upload-time = "2026-05-06T15:11:05.123Z" }, + { url = "https://files.pythonhosted.org/packages/16/21/5a3f1e8913103b703a436a5664238e5b965ec392b555fe68943ea3691e6b/orjson-3.11.9-cp314-cp314-win_arm64.whl", hash = "sha256:eebdbdeef0094e4f5aefa20dcd4eb2368ab5e7a3b4edea27f1e7b2892e009cf9", size = 126687, upload-time = "2026-05-06T15:11:06.602Z" }, ] [[package]] @@ -1252,11 +1416,11 @@ wheels = [ [[package]] name = "packaging" -version = "26.1" +version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] @@ -1275,11 +1439,11 @@ bcrypt = [ [[package]] name = "pathspec" -version = "1.0.4" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] @@ -1342,11 +1506,11 @@ wheels = [ [[package]] name = "pip" -version = "26.0.1" +version = "26.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747, upload-time = "2026-02-05T02:20:18.702Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/91/47e7d486260f618783899587af63ccf7980fb60245c3e63dd4571c6b57ad/pip-26.1.2.tar.gz", hash = "sha256:f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605", size = 1840799, upload-time = "2026-05-31T17:33:58.56Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723, upload-time = "2026-02-05T02:20:16.416Z" }, + { url = "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl", hash = "sha256:382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab", size = 1813144, upload-time = "2026-05-31T17:33:56.772Z" }, ] [[package]] @@ -1396,11 +1560,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.9.6" +version = "4.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, ] [[package]] @@ -1430,71 +1594,79 @@ wheels = [ [[package]] name = "propcache" -version = "0.4.1" +version = "0.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, - { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, - { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, - { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, - { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, - { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, - { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, - { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, - { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, - { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, - { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, - { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, - { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, - { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, - { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, - { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, - { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, - { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, - { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, - { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, - { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, - { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, - { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, - { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, - { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, - { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, - { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, - { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, - { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, - { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, - { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, - { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, - { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, - { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, - { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, - { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, - { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, - { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, - { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, - { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, - { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, - { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, - { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, + { url = "https://files.pythonhosted.org/packages/c5/09/f049e45385503fe67db75a6b6186a7b9f0c3930366dc960522c312a825b1/propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a", size = 94457, upload-time = "2026-05-08T21:00:36.355Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/83d1d05655baf63113731bd5a1008435e14f8d1e5a06cbe4ec5b23ad7a31/propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117", size = 53835, upload-time = "2026-05-08T21:00:38.072Z" }, + { url = "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098", size = 54545, upload-time = "2026-05-08T21:00:39.319Z" }, + { url = "https://files.pythonhosted.org/packages/a9/19/7fa086f5764c59ec8a8e157cd93aa8497acc00aba9dcdec56bfffb32602d/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4", size = 59886, upload-time = "2026-05-08T21:00:40.621Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e4/5d7663dc8235956c8f5281698a3af1d351d8820341ddd890f59d9a9127f2/propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e", size = 63261, upload-time = "2026-05-08T21:00:41.775Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/15a03adee24d6350da4292caeac44c34c033d2afe5e87eb370f38854560f/propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7", size = 64184, upload-time = "2026-05-08T21:00:43.018Z" }, + { url = "https://files.pythonhosted.org/packages/8b/c6/979176efdaa3d239e36d503d5af63a0a773b36662ed8f52e5b6a6d9fd40e/propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d", size = 61534, upload-time = "2026-05-08T21:00:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/c8/22/63e8cd1bae4c2d2be6493b6b7d10566ddafad88137cfbc99964a1119853c/propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a", size = 61500, upload-time = "2026-05-08T21:00:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/60/5a/28e5d9acbac1cc9ccb67045e8c1b943aa8d79fdf39c93bd73cacd68008ea/propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2", size = 59994, upload-time = "2026-05-08T21:00:47.093Z" }, + { url = "https://files.pythonhosted.org/packages/f3/40/db650677f554a95b9c01a7c9d93d629e93a15562f5deb4573c9ee136fed2/propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa", size = 56884, upload-time = "2026-05-08T21:00:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/80/45/70b39b89516ff8b96bf732fa6fded8cef20f293cb1508690101c3c07ec51/propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853", size = 63464, upload-time = "2026-05-08T21:00:49.954Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/fa59d3a89eac5534293124af4f1d0d0ada091ce4a0ab4610ce03fd2bdd8d/propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a", size = 61588, upload-time = "2026-05-08T21:00:51.281Z" }, + { url = "https://files.pythonhosted.org/packages/0b/97/efb547a55c4bc7381cfb202d6a2239ac621045277bc1ea5dfd3a7f0516c0/propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704", size = 64667, upload-time = "2026-05-08T21:00:52.602Z" }, + { url = "https://files.pythonhosted.org/packages/92/56/f5c7d9b4b7595d5127da38974d791b2153f3d1eae6c674af3583ace92ad3/propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4", size = 62463, upload-time = "2026-05-08T21:00:54.303Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3b/484a3a65fc9f9f60c41dcd17b428bace5389544e2c680994534a20755066/propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d", size = 38621, upload-time = "2026-05-08T21:00:55.808Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fd/3f0f10dba4dabad3bf53102be007abf55481067952bde0fdddff439e7c61/propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757", size = 41649, upload-time = "2026-05-08T21:00:57.061Z" }, + { url = "https://files.pythonhosted.org/packages/90/ec/6ce619cc32bb500a482f811f9cd509368b4e58e638d13f2c68f370d6b475/propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f", size = 37636, upload-time = "2026-05-08T21:00:58.646Z" }, + { url = "https://files.pythonhosted.org/packages/1b/82/c1d268bbbf2ef981c5bf0fbbe746db617c66e3bcefe431a1aa8943fbe23a/propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d", size = 98872, upload-time = "2026-05-08T21:00:59.889Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d4/52c871e73e864e6b34c0e2d58ac1ec5ccd149497ddc7ad2137ae98323a35/propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa", size = 56257, upload-time = "2026-05-08T21:01:01.195Z" }, + { url = "https://files.pythonhosted.org/packages/67/f0/9b90ca2a210b3d09bcfcd96ecd0f55545c091535abce2a45de2775cfd357/propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94", size = 56696, upload-time = "2026-05-08T21:01:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0e/6e9d4ba07c8e56e21ddec1e75f12148142b21ca83a51871babce095334f4/propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164", size = 62378, upload-time = "2026-05-08T21:01:04.475Z" }, + { url = "https://files.pythonhosted.org/packages/65/19/c10badaa463dde8a27ce884f8ee2ec37e6035b7c9f5ff0c8f74f06f08dac/propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f", size = 65283, upload-time = "2026-05-08T21:01:05.959Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b6/93bea99ca80e19cef6512a8580e5b7857bbe09422d9daa7fd4ef5723306c/propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c", size = 66616, upload-time = "2026-05-08T21:01:07.228Z" }, + { url = "https://files.pythonhosted.org/packages/83/e4/5c7462e50625f051f37fb38b8224f7639f667184bbd34424ec83819bb1b7/propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc", size = 63773, upload-time = "2026-05-08T21:01:08.514Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/99238894047b13c823be25027e736626cd414a52a5e30d2c3347c2733529/propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f", size = 63664, upload-time = "2026-05-08T21:01:09.874Z" }, + { url = "https://files.pythonhosted.org/packages/85/1e/a3a1a63116a2b8edb415a8bb9a6f0c34bd03830b1e18e8ce2904e1dc1cf4/propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb", size = 62643, upload-time = "2026-05-08T21:01:11.132Z" }, + { url = "https://files.pythonhosted.org/packages/e4/03/893cf147de2fc6543c5eaa07ad833170e7e2a2385725bbebe8c0503723bb/propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751", size = 59595, upload-time = "2026-05-08T21:01:12.387Z" }, + { url = "https://files.pythonhosted.org/packages/86/3b/04c1a2e12c57766568ba75ba72b3bf2042818d4c1425fab6fc07155c7cff/propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836", size = 65711, upload-time = "2026-05-08T21:01:13.676Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/80f8d0099f8d6bacc4de1624c85672681c8cd1149ca2da0e38fd120b817f/propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f", size = 64247, upload-time = "2026-05-08T21:01:14.936Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1a/8b08f3a5f1037e9e370c55883ceeeee0f6dd0416fb2d2d67b8bfc91f2a79/propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55", size = 67102, upload-time = "2026-05-08T21:01:16.281Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/8bdb7bb7756d76e005490649d10e4a8369e610c74d619f71e1aedf889e9c/propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568", size = 64964, upload-time = "2026-05-08T21:01:17.57Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/50fb0b5d3968b61a510926ff8b8465f1d6e976b3ab74496d7a4b9fc42515/propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191", size = 42546, upload-time = "2026-05-08T21:01:18.946Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4c/0ddbae64321bd4a95bcbfc19307238016b5b1fee645c84626c8d539e5b74/propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7", size = 46330, upload-time = "2026-05-08T21:01:20.162Z" }, + { url = "https://files.pythonhosted.org/packages/00/d9/9cddc8efb78d8af264c5ec9f6d10b62f57c515feda8d321595f56010fb23/propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96", size = 40521, upload-time = "2026-05-08T21:01:21.399Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ea/23ee535d90ce8bcc465a3028eb3cc0ce3bd1005f4bb27710b30587de798d/propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999", size = 94662, upload-time = "2026-05-08T21:01:22.683Z" }, + { url = "https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e", size = 53928, upload-time = "2026-05-08T21:01:23.986Z" }, + { url = "https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539", size = 54650, upload-time = "2026-05-08T21:01:25.305Z" }, + { url = "https://files.pythonhosted.org/packages/70/06/2f46c318e3307cd7a6a7481def374ce838c0fe20084b39dd54b0879d0e99/propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e", size = 59912, upload-time = "2026-05-08T21:01:26.545Z" }, + { url = "https://files.pythonhosted.org/packages/4c/29/fe1aebec2ce57ab985a9c382bded1124431f85078113aa222c5d278430d4/propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979", size = 63300, upload-time = "2026-05-08T21:01:27.937Z" }, + { url = "https://files.pythonhosted.org/packages/b4/18/2334b26768b6c82be8c69e83671b767d5ef426aa09b0cba6c2ea47816774/propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80", size = 64208, upload-time = "2026-05-08T21:01:29.484Z" }, + { url = "https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825", size = 61633, upload-time = "2026-05-08T21:01:31.068Z" }, + { url = "https://files.pythonhosted.org/packages/c4/46/b3ff8aba2b4953a3e50de2cf72f1b5748b8eca93b15f3dc2c84339084c09/propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39", size = 61724, upload-time = "2026-05-08T21:01:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/c5/01/814cfcafbcff954f94c01cf30e097ddc88a076b5440fbcf4570753437d40/propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4", size = 60069, upload-time = "2026-05-08T21:01:33.67Z" }, + { url = "https://files.pythonhosted.org/packages/da/68/5c6f7622d510cc666a300687e06fd060c1a43361c0c9b20d284f06d8096a/propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5", size = 57099, upload-time = "2026-05-08T21:01:34.915Z" }, + { url = "https://files.pythonhosted.org/packages/55/27/9cb0b4c679124085327957d42521c99dba04c88c90c3e55a6f0b633ebccc/propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702", size = 63391, upload-time = "2026-05-08T21:01:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9d/7258aaa5bdf60fc6f27591eef6fe52768cb0beda7140be477c8b12c9794a/propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3", size = 61626, upload-time = "2026-05-08T21:01:37.545Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/41c602003e8a9b16fe1e7eadf62c7bfba9d5474370b24200bf48b315f45f/propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5", size = 64781, upload-time = "2026-05-08T21:01:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f3/38e66b1856e9bd079deea015bc4a55f7767c0e4db2f7dcf69e7e680ba4ce/propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4", size = 62570, upload-time = "2026-05-08T21:01:40.415Z" }, + { url = "https://files.pythonhosted.org/packages/95/ca/bbfe9b910ce57dde8bb4876b4520fc02a4e89497c10de26be936758a3aaa/propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0", size = 39436, upload-time = "2026-05-08T21:01:41.654Z" }, + { url = "https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c", size = 42373, upload-time = "2026-05-08T21:01:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/44/68/9ea5103f41d5217d7d6ec24db90018e23aebec070c3f9a6e54d12b841fd8/propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0", size = 38554, upload-time = "2026-05-08T21:01:44.336Z" }, + { url = "https://files.pythonhosted.org/packages/8a/81/fadf555f42d3b762eea8a53950b0489fdc0aa9da5f8ed9e10ce0a4e01b48/propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb", size = 99395, upload-time = "2026-05-08T21:01:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c9/c61e134a686949cf7971af3a390148b1156f7be81c73bc0cd12c873e2d48/propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078", size = 56653, upload-time = "2026-05-08T21:01:47.307Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa", size = 56914, upload-time = "2026-05-08T21:01:48.573Z" }, + { url = "https://files.pythonhosted.org/packages/79/9f/aba959b435ea18617edd7cf0a7ad0b9c574b8fc7e3d2cd55fb59cb255d33/propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917", size = 62567, upload-time = "2026-05-08T21:01:49.903Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a1/859942de9a791ff42f6141736f5b37749b8f53e65edfa49638c67dd67e6a/propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe", size = 65542, upload-time = "2026-05-08T21:01:51.204Z" }, + { url = "https://files.pythonhosted.org/packages/b5/61/315bc0fd6c0fc7f80a528b8afd209e5fc4a875ea79571b91b8f50f442907/propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03", size = 66845, upload-time = "2026-05-08T21:01:52.539Z" }, + { url = "https://files.pythonhosted.org/packages/47/f7/9f8122e3132e8e354ac41975ef8f1099be7d5a16bc7ae562734e993665c0/propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335", size = 63985, upload-time = "2026-05-08T21:01:53.847Z" }, + { url = "https://files.pythonhosted.org/packages/c8/54/c317819ec157cbf6f35df9df9657a6f82daf34d5faf15948b2f639c2192e/propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285", size = 63999, upload-time = "2026-05-08T21:01:55.179Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/387e3f7dfce0a9233df41fb888aa1c30222cb4bbbf09537c02dd9bd85fe2/propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837", size = 62779, upload-time = "2026-05-08T21:01:57.489Z" }, + { url = "https://files.pythonhosted.org/packages/a1/9c/596784cb5824ed61ee960d3f8655a3f0993e107c6e98ab6c818b7fb92ccb/propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8", size = 59796, upload-time = "2026-05-08T21:01:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/c2/3d/1a6cfa1726a48542c1e8784a0761421476a5b68e09b7f36bf95eb954aaba/propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366", size = 66023, upload-time = "2026-05-08T21:02:00.228Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0e/05fd6990369477076e4e280bcb970de760fddf0161a46e988bc95f7940ec/propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56", size = 64448, upload-time = "2026-05-08T21:02:01.888Z" }, + { url = "https://files.pythonhosted.org/packages/cd/86/5f8da315a4309c62c10c0b2516b17492d5d3bbe1bb862b96604db67e2a37/propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d", size = 67329, upload-time = "2026-05-08T21:02:03.484Z" }, + { url = "https://files.pythonhosted.org/packages/da/d3/3368efe79ab21f0cdf86ef49895811c9cc933131d4cde1f28a624e22e712/propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2", size = 65172, upload-time = "2026-05-08T21:02:04.745Z" }, + { url = "https://files.pythonhosted.org/packages/d5/07/127e8b0bacfb325396196f9d976a22453049b89b9b2b08477cc3145faa44/propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821", size = 43813, upload-time = "2026-05-08T21:02:06.025Z" }, + { url = "https://files.pythonhosted.org/packages/88/fb/46dad6c0ae49ed230ab1b16c890c2b6314e2403e6c412976f4a72d64a527/propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370", size = 47764, upload-time = "2026-05-08T21:02:07.353Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c4/a47d0a63aa309d10d59ede6e9d4cff03a344a79d1f0f4cd0cd74997b53e0/propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6", size = 41140, upload-time = "2026-05-08T21:02:09.065Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, ] [[package]] @@ -1539,6 +1711,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/f2/3483060562245668bb07193b65277f0ea619cabf530deb351911eb0453eb/py_serializable-1.1.2-py3-none-any.whl", hash = "sha256:801be61b0a1ba64c3861f7c624f1de5cfbbabf8b458acc9cdda91e8f7e5effa1", size = 22786, upload-time = "2024-10-01T15:55:42.498Z" }, ] +[[package]] +name = "pyasn1" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, +] + [[package]] name = "pycparser" version = "3.0" @@ -1609,11 +1790,11 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, ] [[package]] @@ -1627,42 +1808,44 @@ wheels = [ [[package]] name = "pytest" -version = "8.3.5" +version = "9.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, + { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] [[package]] name = "pytest-asyncio" -version = "0.24.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855, upload-time = "2024-08-22T08:03:18.145Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024, upload-time = "2024-08-22T08:03:15.536Z" }, + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, ] [[package]] name = "pytest-cov" -version = "6.0.0" +version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, + { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] [[package]] @@ -1679,15 +1862,15 @@ wheels = [ [[package]] name = "python-discovery" -version = "1.2.2" +version = "1.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/cbbaf13b730abb0a16b964d984e19f2fe520c21a4dc664051359a3f5a9e7/python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690", size = 70277, upload-time = "2026-06-11T16:10:42.383Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, + { url = "https://files.pythonhosted.org/packages/1a/82/a70006589557f267f15bd384c0642ad49f0d97b690c3a05b166b9dcbad3b/python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500", size = 33886, upload-time = "2026-06-11T16:10:41.192Z" }, ] [[package]] @@ -1701,11 +1884,35 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.26" +version = "0.0.32" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/71/b145a380824a960ebd60e1014256dbb7d2253f2316ff2d73dfd8928ec2c3/python_multipart-0.0.26.tar.gz", hash = "sha256:08fadc45918cd615e26846437f50c5d6d23304da32c341f289a617127b081f17", size = 43501, upload-time = "2026-04-10T14:09:59.473Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl", hash = "sha256:c0b169f8c4484c13b0dcf2ef0ec3a4adb255c4b7d18d8e420477d2b1dd03f185", size = 28847, upload-time = "2026-04-10T14:09:58.131Z" }, + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "pytokens" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" }, + { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, + { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, + { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, + { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, + { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, + { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] [[package]] @@ -1767,7 +1974,7 @@ wheels = [ [[package]] name = "requests" -version = "2.33.1" +version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1775,9 +1982,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] [[package]] @@ -1795,27 +2002,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.8.6" +version = "0.15.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/00/089db7890ea3be5709e3ece6e46408d6f1e876026ec3fd081ee585fef209/ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", size = 3473116, upload-time = "2025-01-04T12:23:00.794Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/28/aa07903694637c2fa394a9f4fe93cf861ad8b09f1282fa650ef07ff9fe97/ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", size = 10628735, upload-time = "2025-01-04T12:21:53.632Z" }, - { url = "https://files.pythonhosted.org/packages/2b/43/827bb1448f1fcb0fb42e9c6edf8fb067ca8244923bf0ddf12b7bf949065c/ruff-0.8.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", size = 10386758, upload-time = "2025-01-04T12:22:00.349Z" }, - { url = "https://files.pythonhosted.org/packages/df/93/fc852a81c3cd315b14676db3b8327d2bb2d7508649ad60bfdb966d60738d/ruff-0.8.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", size = 10007808, upload-time = "2025-01-04T12:22:04.413Z" }, - { url = "https://files.pythonhosted.org/packages/94/e9/e0ed4af1794335fb280c4fac180f2bf40f6a3b859cae93a5a3ada27325ae/ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", size = 10861031, upload-time = "2025-01-04T12:22:09.252Z" }, - { url = "https://files.pythonhosted.org/packages/82/68/da0db02f5ecb2ce912c2bef2aa9fcb8915c31e9bc363969cfaaddbc4c1c2/ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", size = 10388246, upload-time = "2025-01-04T12:22:12.63Z" }, - { url = "https://files.pythonhosted.org/packages/ac/1d/b85383db181639019b50eb277c2ee48f9f5168f4f7c287376f2b6e2a6dc2/ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", size = 11424693, upload-time = "2025-01-04T12:22:17.244Z" }, - { url = "https://files.pythonhosted.org/packages/ac/b7/30bc78a37648d31bfc7ba7105b108cb9091cd925f249aa533038ebc5a96f/ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", size = 12141921, upload-time = "2025-01-04T12:22:20.456Z" }, - { url = "https://files.pythonhosted.org/packages/60/b3/ee0a14cf6a1fbd6965b601c88d5625d250b97caf0534181e151504498f86/ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", size = 11692419, upload-time = "2025-01-04T12:22:23.62Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d6/c597062b2931ba3e3861e80bd2b147ca12b3370afc3889af46f29209037f/ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", size = 12981648, upload-time = "2025-01-04T12:22:26.663Z" }, - { url = "https://files.pythonhosted.org/packages/68/84/21f578c2a4144917985f1f4011171aeff94ab18dfa5303ac632da2f9af36/ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", size = 11251801, upload-time = "2025-01-04T12:22:29.59Z" }, - { url = "https://files.pythonhosted.org/packages/6c/aa/1ac02537c8edeb13e0955b5db86b5c050a1dcba54f6d49ab567decaa59c1/ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", size = 10849857, upload-time = "2025-01-04T12:22:33.536Z" }, - { url = "https://files.pythonhosted.org/packages/eb/00/020cb222252d833956cb3b07e0e40c9d4b984fbb2dc3923075c8f944497d/ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", size = 10470852, upload-time = "2025-01-04T12:22:36.374Z" }, - { url = "https://files.pythonhosted.org/packages/00/56/e6d6578202a0141cd52299fe5acb38b2d873565f4670c7a5373b637cf58d/ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", size = 10972997, upload-time = "2025-01-04T12:22:41.424Z" }, - { url = "https://files.pythonhosted.org/packages/be/31/dd0db1f4796bda30dea7592f106f3a67a8f00bcd3a50df889fbac58e2786/ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", size = 11317760, upload-time = "2025-01-04T12:22:44.541Z" }, - { url = "https://files.pythonhosted.org/packages/d4/70/cfcb693dc294e034c6fed837fa2ec98b27cc97a26db5d049345364f504bf/ruff-0.8.6-py3-none-win32.whl", hash = "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", size = 8799729, upload-time = "2025-01-04T12:22:49.016Z" }, - { url = "https://files.pythonhosted.org/packages/60/22/ae6bcaa0edc83af42751bd193138bfb7598b2990939d3e40494d6c00698c/ruff-0.8.6-py3-none-win_amd64.whl", hash = "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905", size = 9673857, upload-time = "2025-01-04T12:22:53.052Z" }, - { url = "https://files.pythonhosted.org/packages/91/f8/3765e053acd07baa055c96b2065c7fab91f911b3c076dfea71006666f5b0/ruff-0.8.6-py3-none-win_arm64.whl", hash = "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", size = 9149556, upload-time = "2025-01-04T12:22:57.173Z" }, + { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, + { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, + { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, + { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, + { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, + { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, + { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, ] [[package]] @@ -1847,41 +2054,36 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.49" +version = "2.0.50" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/da/6fbf010c8ebb347679d0d100b22fe9ba5e13fd04046c5df7280d2f0bf706/sqlalchemy-2.0.50.tar.gz", hash = "sha256:af5607d11ef90fd6a5c0549fe0045dce1663d427426bcfb506dcb5346a85a3b9", size = 9907424, upload-time = "2026-05-24T19:20:04.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/81/81755f50eb2478eaf2049728491d4ea4f416c1eb013338682173259efa09/sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120", size = 2154547, upload-time = "2026-04-03T16:53:08.64Z" }, - { url = "https://files.pythonhosted.org/packages/a2/bc/3494270da80811d08bcfa247404292428c4fe16294932bce5593f215cad9/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2", size = 3280782, upload-time = "2026-04-03T17:07:43.508Z" }, - { url = "https://files.pythonhosted.org/packages/cd/f5/038741f5e747a5f6ea3e72487211579d8cbea5eb9827a9cbd61d0108c4bd/sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3", size = 3297156, upload-time = "2026-04-03T17:12:27.697Z" }, - { url = "https://files.pythonhosted.org/packages/88/50/a6af0ff9dc954b43a65ca9b5367334e45d99684c90a3d3413fc19a02d43c/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7", size = 3228832, upload-time = "2026-04-03T17:07:45.38Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d1/5f6bdad8de0bf546fc74370939621396515e0cdb9067402d6ba1b8afbe9a/sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33", size = 3267000, upload-time = "2026-04-03T17:12:29.657Z" }, - { url = "https://files.pythonhosted.org/packages/f7/30/ad62227b4a9819a5e1c6abff77c0f614fa7c9326e5a3bdbee90f7139382b/sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b", size = 2115641, upload-time = "2026-04-03T17:05:43.989Z" }, - { url = "https://files.pythonhosted.org/packages/17/3a/7215b1b7d6d49dc9a87211be44562077f5f04f9bb5a59552c1c8e2d98173/sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148", size = 2141498, upload-time = "2026-04-03T17:05:45.7Z" }, - { url = "https://files.pythonhosted.org/packages/28/4b/52a0cb2687a9cd1648252bb257be5a1ba2c2ded20ba695c65756a55a15a4/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518", size = 3560807, upload-time = "2026-04-03T16:58:31.666Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d8/fda95459204877eed0458550d6c7c64c98cc50c2d8d618026737de9ed41a/sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d", size = 3527481, upload-time = "2026-04-03T17:06:00.155Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0a/2aac8b78ac6487240cf7afef8f203ca783e8796002dc0cf65c4ee99ff8bb/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0", size = 3468565, upload-time = "2026-04-03T16:58:33.414Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3d/ce71cfa82c50a373fd2148b3c870be05027155ce791dc9a5dcf439790b8b/sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08", size = 3477769, upload-time = "2026-04-03T17:06:02.787Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e8/0a9f5c1f7c6f9ca480319bf57c2d7423f08d31445974167a27d14483c948/sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d", size = 2143319, upload-time = "2026-04-03T17:02:04.328Z" }, - { url = "https://files.pythonhosted.org/packages/0e/51/fb5240729fbec73006e137c4f7a7918ffd583ab08921e6ff81a999d6517a/sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba", size = 2175104, upload-time = "2026-04-03T17:02:05.989Z" }, - { url = "https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e", size = 2156356, upload-time = "2026-04-03T16:53:09.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a7/5f476227576cb8644650eff68cc35fa837d3802b997465c96b8340ced1e2/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a", size = 3276486, upload-time = "2026-04-03T17:07:46.9Z" }, - { url = "https://files.pythonhosted.org/packages/2e/84/efc7c0bf3a1c5eef81d397f6fddac855becdbb11cb38ff957888603014a7/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066", size = 3281479, upload-time = "2026-04-03T17:12:32.226Z" }, - { url = "https://files.pythonhosted.org/packages/91/68/bb406fa4257099c67bd75f3f2261b129c63204b9155de0d450b37f004698/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187", size = 3226269, upload-time = "2026-04-03T17:07:48.678Z" }, - { url = "https://files.pythonhosted.org/packages/67/84/acb56c00cca9f251f437cb49e718e14f7687505749ea9255d7bd8158a6df/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401", size = 3248260, upload-time = "2026-04-03T17:12:34.381Z" }, - { url = "https://files.pythonhosted.org/packages/56/19/6a20ea25606d1efd7bd1862149bb2a22d1451c3f851d23d887969201633f/sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5", size = 2118463, upload-time = "2026-04-03T17:05:47.093Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4f/8297e4ed88e80baa1f5aa3c484a0ee29ef3c69c7582f206c916973b75057/sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", size = 2144204, upload-time = "2026-04-03T17:05:48.694Z" }, - { url = "https://files.pythonhosted.org/packages/1f/33/95e7216df810c706e0cd3655a778604bbd319ed4f43333127d465a46862d/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977", size = 3565474, upload-time = "2026-04-03T16:58:35.128Z" }, - { url = "https://files.pythonhosted.org/packages/0c/a4/ed7b18d8ccf7f954a83af6bb73866f5bc6f5636f44c7731fbb741f72cc4f/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01", size = 3530567, upload-time = "2026-04-03T17:06:04.587Z" }, - { url = "https://files.pythonhosted.org/packages/73/a3/20faa869c7e21a827c4a2a42b41353a54b0f9f5e96df5087629c306df71e/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61", size = 3474282, upload-time = "2026-04-03T16:58:37.131Z" }, - { url = "https://files.pythonhosted.org/packages/b7/50/276b9a007aa0764304ad467eceb70b04822dc32092492ee5f322d559a4dc/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a", size = 3480406, upload-time = "2026-04-03T17:06:07.176Z" }, - { url = "https://files.pythonhosted.org/packages/e5/c3/c80fcdb41905a2df650c2a3e0337198b6848876e63d66fe9188ef9003d24/sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158", size = 2149151, upload-time = "2026-04-03T17:02:07.281Z" }, - { url = "https://files.pythonhosted.org/packages/05/52/9f1a62feab6ed368aff068524ff414f26a6daebc7361861035ae00b05530/sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7", size = 2184178, upload-time = "2026-04-03T17:02:08.623Z" }, - { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c4/c42356b527296e9862f67990efce31ef78b4cf69cd3f80873a528a060320/sqlalchemy-2.0.50-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:06a9210bdc5f4298cff0781087e2ff45683922252dacc452846373a58761f093", size = 2156697, upload-time = "2026-05-24T19:27:54.764Z" }, + { url = "https://files.pythonhosted.org/packages/60/a1/b1a70e3c4365ac7fe9e347f3710f19b562c866fb96d45e3c891588789a7b/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b53784972ade4f8174b9aa661f31a06f8a936d2cfdd602913ff3c6dd40ae873", size = 3284260, upload-time = "2026-05-24T20:09:34.195Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4a/f3ac3caa19f263d57b0a47f8c91bbf56583dc2d3fc63acfbf644abb24fe0/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31648fa14460537e768a7303b078e4344d208e0d23e06867c1f376a227ed82db", size = 3302280, upload-time = "2026-05-24T20:17:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/66/55/ccada3e3d62254587819749a0bc69f41173eb48a6e385d10e66d32a9c88e/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:03f4323c980ad0e918cc9e5369b015f759f4e534db5bbaf4dc36832c10d05064", size = 3231580, upload-time = "2026-05-24T20:09:36.406Z" }, + { url = "https://files.pythonhosted.org/packages/05/f6/6809349130a2de0e109e7f00fd7d431da9565b9b2868b32ee684754f672b/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2b9dcc43afef8ac157cd92fce96985d6b8b0cfbd3df4d666f66b4d55a75d202f", size = 3269375, upload-time = "2026-05-24T20:17:20.34Z" }, + { url = "https://files.pythonhosted.org/packages/48/84/278a811ef4e07be9c89dc5cdd7be833268509a66a68c4897cf585e67428f/sqlalchemy-2.0.50-cp313-cp313-win32.whl", hash = "sha256:60922d6599065ddca2c6f376b9aa2f41a6b85a271725e0909490bbc50b1998a5", size = 2117229, upload-time = "2026-05-24T19:50:08.215Z" }, + { url = "https://files.pythonhosted.org/packages/f6/1c/067cc6187ed32d2ec222fe6d2643acc1659a6d0659f8a7cbc5ad3ae83280/sqlalchemy-2.0.50-cp313-cp313-win_amd64.whl", hash = "sha256:287086e67275a212c4582d166a6fb03a65ccc5551d80866270ce0dd9f34eccd3", size = 2143126, upload-time = "2026-05-24T19:50:09.691Z" }, + { url = "https://files.pythonhosted.org/packages/df/32/10ac51b4be7cdecd7e93d069251c86dfbf70b7adbd7c67b48ccea6c49e1c/sqlalchemy-2.0.50-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c966932507a4d7d0a37314927dbfcd89720e3f37d2a1e3352e7ae7939fa8e8a0", size = 2158519, upload-time = "2026-05-24T19:27:56.472Z" }, + { url = "https://files.pythonhosted.org/packages/5a/76/e703d2f7681d7d66c4c891af3f07c7ccf4c76ad7f18351de035b5eda007a/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:faffef4bcc20a1892e65e155293d99d60855bbbc79250ab712819cfd56a8e6bb", size = 3282063, upload-time = "2026-05-24T20:09:38.57Z" }, + { url = "https://files.pythonhosted.org/packages/31/26/ef168b184a25701f9995e8fb7e503fafd7a99c1c77cda1bc1a26ea2ed486/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c206aec519a2e7bd08abbfb33436e325fd22c632d9c21a9047e376ce241646e", size = 3287069, upload-time = "2026-05-24T20:17:21.942Z" }, + { url = "https://files.pythonhosted.org/packages/c2/15/765acc2bc693bccc43ca4a95d5b69750da8aaf6db1b5c616536e087f8920/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bef4ac756363227ef6402a75fee025a4bc690f92328e825868939b3b3a446a6d", size = 3230453, upload-time = "2026-05-24T20:09:40.398Z" }, + { url = "https://files.pythonhosted.org/packages/63/61/08e03c3adbf5db0087a0b6816746fec8f3032fb2f7fc899a9bb9b2a48ce4/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96fbee6b19c19cd1556c8bf9419447cf2ec149ffcab7ab64348c23e54ef8547f", size = 3252413, upload-time = "2026-05-24T20:17:24.067Z" }, + { url = "https://files.pythonhosted.org/packages/03/0c/370a1f2db38436c615e10134c8a37de3688e74084792380695f3f5083860/sqlalchemy-2.0.50-cp314-cp314-win32.whl", hash = "sha256:8f00e3eb43ba30eb1b238ee03a8a62309486d1321eda3328bb611e0340033ad8", size = 2120063, upload-time = "2026-05-24T19:50:11.08Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a0/fe92bb9817863bc13ba093bda931979a26cc2ca69f8e8f26d07add3d7c6f/sqlalchemy-2.0.50-cp314-cp314-win_amd64.whl", hash = "sha256:15708c613cd5005b7dffe1f66ee6a63ee8f5e46799f71c70ebad74178c676a39", size = 2145830, upload-time = "2026-05-24T19:50:12.452Z" }, + { url = "https://files.pythonhosted.org/packages/cc/ff/e5640a98a0b2f491eb8fde10fb6c773621a2e44340de231fafcc9370f4a9/sqlalchemy-2.0.50-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3699dac4be410e97049a1658e9480da9cde956594aa0f3aebc60b88f21c5ba70", size = 2178435, upload-time = "2026-05-24T19:42:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/b7/85/337116e186f1236375b5fb70c21cfac98e8e8ab0d3a47be838dc47a59e08/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f96233858e3df43932ac11589e22520da6e8aeb624b03fedfeebb0e8ea213086", size = 3566059, upload-time = "2026-05-24T20:01:20.848Z" }, + { url = "https://files.pythonhosted.org/packages/96/34/bb0e190e161c3c2c24314a65add57218be14a4a9486886b7f5047c1ff7c8/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c4e70c46fad30c3bcc6a4708bc0130a3173e11a5b25f0ea4a9d8911b450f1f52", size = 3535366, upload-time = "2026-05-24T20:03:56.768Z" }, + { url = "https://files.pythonhosted.org/packages/df/5a/a7f759f97e4fd499c5d4e4488c760d5a7fbecf3028b465a04274fcd52384/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1918a3cf564d16d95bca7301005f41ab2ad50b07cd3b9da50d3ed986db148d6a", size = 3474879, upload-time = "2026-05-24T20:01:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d9/2907ea38eb60687d297bf9c39e5ee58053c87b57fe8a9cae97090cecbf10/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b00098cdbdbd38c7be3d568b0c9c3122b8c0ec62b911b57cd5e6e0254d60a76d", size = 3486117, upload-time = "2026-05-24T20:03:59.052Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e3/5aa06f167559f8c0bdae487e297d23ba548150ab016a3418265d617a4985/sqlalchemy-2.0.50-cp314-cp314t-win32.whl", hash = "sha256:1fbd55a969d7ac44a98e3dec75016074f809fa08f871585ace58dde110d1bf3e", size = 2150823, upload-time = "2026-05-24T20:08:58.644Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/112fb8f977582d7489d036e409e3723948bcf5320b3ac465f3c481bbe8f9/sqlalchemy-2.0.50-cp314-cp314t-win_amd64.whl", hash = "sha256:c5c3cdb753a9004183e1ccb634b41611654c989e61bc68617ce878e46d6f1e51", size = 2185794, upload-time = "2026-05-24T20:09:00.319Z" }, + { url = "https://files.pythonhosted.org/packages/d0/10/f7220e9b784d295d241c86ed99aeb537f92afcd469a64861f2717e9bb077/sqlalchemy-2.0.50-py3-none-any.whl", hash = "sha256:92064363517a3ff8212b5a93b8c62876579d8dfd1ca5b561335f30152d884fa9", size = 1943861, upload-time = "2026-05-24T19:59:01.119Z" }, ] [package.optional-dependencies] @@ -1891,23 +2093,23 @@ asyncio = [ [[package]] name = "starlette" -version = "1.0.0" +version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/69/17425771797c36cded50b7fe44e850315d039f28b15901ab44839e70b593/starlette-1.0.0.tar.gz", hash = "sha256:6a4beaf1f81bb472fd19ea9b918b50dc3a77a6f2e190a12954b25e6ed5eea149", size = 2655289, upload-time = "2026-03-22T18:29:46.779Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/37/cc24e33974e1439cf5ca62b0735b63026eabb768f472d8775f52d5851ed9/starlette-1.3.0.tar.gz", hash = "sha256:bb58cbb7a699da4ee4be9ed4cdfe4bc5b0390aa6dac1d1ac714ebebe8dc3c8df", size = 2702493, upload-time = "2026-06-11T06:27:41.869Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl", hash = "sha256:d3ec55e0bb321692d275455ddfd3df75fff145d009685eb40dc91fc66b03d38b", size = 72651, upload-time = "2026-03-22T18:29:45.111Z" }, + { url = "https://files.pythonhosted.org/packages/16/42/56d31c5ee52dab0ad893d67d4f9c00f5ba2b4c5d87f392eca2c3fdce01cf/starlette-1.3.0-py3-none-any.whl", hash = "sha256:ff4ca1bc23de6a45cdfbbeb9b3caaea524c9221cdd8a6684ad7a4f651a83890b", size = 73492, upload-time = "2026-06-11T06:27:40.444Z" }, ] [[package]] name = "stevedore" -version = "5.7.0" +version = "5.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6d/90764092216fa560f6587f83bb70113a8ba510ba436c6476a2b47359057c/stevedore-5.7.0.tar.gz", hash = "sha256:31dd6fe6b3cbe921e21dcefabc9a5f1cf848cf538a1f27543721b8ca09948aa3", size = 516200, upload-time = "2026-02-20T13:27:06.765Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/88/35e4d27d9177d7df76d060e0a18f69c6c5794c96960c94042e20a12c8ba2/stevedore-5.8.0.tar.gz", hash = "sha256:b49867b32ca3016e94100e68dbf26e72aa7b8708d0a3f73c08aeb220370ac715", size = 514710, upload-time = "2026-05-18T09:15:27.731Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/06/36d260a695f383345ab5bbc3fd447249594ae2fa8dfd19c533d5ae23f46b/stevedore-5.7.0-py3-none-any.whl", hash = "sha256:fd25efbb32f1abb4c9e502f385f0018632baac11f9ee5d1b70f88cc5e22ad4ed", size = 54483, upload-time = "2026-02-20T13:27:05.561Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ac/19f9941c74add59d17694930ec8105d5eddeee4ce56dd8632b765ca16d6c/stevedore-5.8.0-py3-none-any.whl", hash = "sha256:88eede9e66ca80e34085b9174e2327da2c61ac91f24f70e41c3ad76e4bb4872b", size = 54553, upload-time = "2026-05-18T09:15:25.82Z" }, ] [[package]] @@ -1930,14 +2132,14 @@ wheels = [ [[package]] name = "tqdm" -version = "4.67.3" +version = "4.68.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/05/0d5260f1f1ca784f4a4a0def9cbe6affe587f5b4025328d446c3d67765f4/tqdm-4.68.2.tar.gz", hash = "sha256:89c230e8dbc67c7615c142487111222f878c77427ea09549960f62389e258add", size = 171923, upload-time = "2026-06-09T13:26:42.539Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, + { url = "https://files.pythonhosted.org/packages/eb/75/1a0392bcc21c44dcdf87b3cf2d137e7829be2c083a1e38d44efca3d57a16/tqdm-4.68.2-py3-none-any.whl", hash = "sha256:d4240441fb5353290b87d6a85968c9decc131a99b8c7faa28269d829de669ede", size = 78578, upload-time = "2026-06-09T13:26:40.731Z" }, ] [[package]] @@ -1963,11 +2165,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] [[package]] @@ -2022,7 +2224,7 @@ wheels = [ [[package]] name = "virtualenv" -version = "21.2.4" +version = "21.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, @@ -2030,14 +2232,14 @@ dependencies = [ { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/98/3a7e644e19cb26133488caff231be390579860bbbb3da35913c49a1d0a46/virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada", size = 5850742, upload-time = "2026-04-14T22:15:31.438Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/50/7564c805bb8966d9771caaba8a143fa5e57c848ce4e7fdf2d55a1feb2ead/virtualenv-21.4.3.tar.gz", hash = "sha256:938ff0fd3f4e0f0d3a025f67a3d2f25e3c3aabbcd5857ea6170619138d72d141", size = 7644454, upload-time = "2026-06-11T16:47:04.843Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/8d/edd0bd910ff803c308ee9a6b7778621af0d10252219ad9f19ef4d4982a61/virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac", size = 5831232, upload-time = "2026-04-14T22:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8d/84b0d07c6b5f685f85ddf6c87a59d3a8a895a3dfd89e759666fabe951b94/virtualenv-21.4.3-py3-none-any.whl", hash = "sha256:75f4127d4067397c64f38579ce918fec6bf9ca2cd4f48685e82952cc3c035840", size = 7625544, upload-time = "2026-06-11T16:47:01.78Z" }, ] [[package]] name = "volcengine-python-sdk" -version = "5.0.25" +version = "5.0.34" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -2045,9 +2247,9 @@ dependencies = [ { name = "six" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/47/b212f7c834155de1e68e8557080a445392a68e41b11cda2957d7837001eb/volcengine_python_sdk-5.0.25.tar.gz", hash = "sha256:c93f86c3638e277a19465d67d64f5222b1b506430f25b153289d6b1b705e9abd", size = 8661219, upload-time = "2026-04-23T12:58:50.569Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/dc/270126c59f91434184e3dac17e1945f0f4db114cfaea0e149aae9dd079d6/volcengine_python_sdk-5.0.34.tar.gz", hash = "sha256:ad69fe638bf2f192f3a8f7495bcb0387677e737bf6909d7f460006f7b35b7fc5", size = 9577866, upload-time = "2026-06-11T09:55:34.763Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/28/4ab6e1f4241f3bf84aacf0a3777ddd69fe28b662a0c6a56cf932c9064ddc/volcengine_python_sdk-5.0.25-py2.py3-none-any.whl", hash = "sha256:348dbb1cb11e922bebf8360fc61a189e7d6f8be4b8211423ead3a2953eed7755", size = 34196029, upload-time = "2026-04-23T12:58:43.948Z" }, + { url = "https://files.pythonhosted.org/packages/c1/7b/e106e6855ceacdfe089a2e17e9c1862d790eb28905a827ee1aaa36fe40be/volcengine_python_sdk-5.0.34-py2.py3-none-any.whl", hash = "sha256:e243fc077ccc25c37feba9b9303ee7d6817c90caa1c17cc8984d9d4f84109b15", size = 38414817, upload-time = "2026-06-11T09:55:28.626Z" }, ] [package.optional-dependencies] @@ -2060,59 +2262,74 @@ ark = [ [[package]] name = "watchfiles" -version = "1.1.1" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/41/5e1a4bb12aac5f1493fa1bdc11154eca3b258ca4eba65d39c473fe19d8e9/watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838", size = 108252, upload-time = "2026-05-18T04:32:04.251Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, - { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, - { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, - { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, - { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, - { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, - { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, - { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, - { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, - { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, - { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, - { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, - { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, - { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, - { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, - { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, - { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, - { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, - { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, - { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, - { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, - { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, - { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, - { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, - { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, - { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, - { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, - { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, - { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, - { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, + { url = "https://files.pythonhosted.org/packages/d1/4d/70a7feced9f87e2ff26dba42667290f41694fc64646c67261fbb8cab5d5c/watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98", size = 399730, upload-time = "2026-05-18T04:31:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44", size = 392842, upload-time = "2026-05-18T04:30:27.051Z" }, + { url = "https://files.pythonhosted.org/packages/db/ef/d5bdb705c224dbc256aa0c1ec47bf4e61ec52558f2afb44a71a1fe4d7015/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658", size = 452989, upload-time = "2026-05-18T04:31:11.945Z" }, + { url = "https://files.pythonhosted.org/packages/71/29/5495f2c1661949ef7a35e4d71111d129cfe7606414a26887a919d0a55406/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb", size = 458978, upload-time = "2026-05-18T04:30:52.606Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/7f9c07c433811c2fffd93e13fdfb7135de9aab5f2ae41be08960fa0047dc/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f", size = 490248, upload-time = "2026-05-18T04:31:36.003Z" }, + { url = "https://files.pythonhosted.org/packages/3c/11/d93632febc52fbc21be90231bb7c17fd5387f46c9076fd40a5f9c2ae6910/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0", size = 571847, upload-time = "2026-05-18T04:31:10.862Z" }, + { url = "https://files.pythonhosted.org/packages/55/b4/383173e73aabb07ad1d9c7aa859d95437ac46a6d6a1e11005facda0c9d19/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5", size = 465974, upload-time = "2026-05-18T04:30:17.006Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71", size = 454782, upload-time = "2026-05-18T04:30:35.656Z" }, + { url = "https://files.pythonhosted.org/packages/24/62/1732118367cfff0a9fce3bf62ff4bfded09ef5df21d9d446b858b3f70a96/watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3", size = 465182, upload-time = "2026-05-18T04:30:20.846Z" }, + { url = "https://files.pythonhosted.org/packages/28/96/716f7e5f51339bf22963f3345f9f27d7f3b30e2eadc597e257c881dd3c53/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0", size = 629841, upload-time = "2026-05-18T04:31:05.397Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fe/c40783950fd771ccf66ab3ec2722d188a9af1c7f96c6e811f36e40c6e03f/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427", size = 658028, upload-time = "2026-05-18T04:31:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/71/72/4508db1856d1d87fcbb3b63f4839bab1b5682cb0e8d224d122263c09654a/watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799", size = 275183, upload-time = "2026-05-18T04:30:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/f9/36/14b76ca57652e5cc5fd1c11f32a261292c08a0d19a00351013c2549cbfb2/watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9", size = 288059, upload-time = "2026-05-18T04:32:07.937Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8d/0a85e395398d8d20fadfe5c5d32c726eee17a519e78fb356f2cf7531bffe/watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077", size = 280186, upload-time = "2026-05-18T04:31:54.484Z" }, + { url = "https://files.pythonhosted.org/packages/37/68/36db056f1fdcc5f07302f56e631774d6835bcd6fa3ace402304621d5f9e5/watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08", size = 399031, upload-time = "2026-05-18T04:30:44.576Z" }, + { url = "https://files.pythonhosted.org/packages/c1/64/01a9d6f66a82a5c101ce939274106cc72759d62427e153f01edd2b9f87c2/watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9", size = 391205, upload-time = "2026-05-18T04:30:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/84/2c/0a44fe058cb4bb7b8ede6b6670698bbb7c0400740e378d00022189b7b31d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4", size = 451892, upload-time = "2026-05-18T04:32:14.005Z" }, + { url = "https://files.pythonhosted.org/packages/67/a1/351e0d56cd35e6488b5c8b4fb11a809a5bc923e8fe8fed9faf8920be0c89/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55", size = 458867, upload-time = "2026-05-18T04:31:22.279Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/9d09605187f1b838998624049fcf8bf47b73c1a3b76901fcac1782f62277/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925", size = 490217, upload-time = "2026-05-18T04:31:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/60/5d/a17a16eccb182f04188cd308ec24b1a71a9b5c4e7098269cf35d9fa56d02/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4", size = 571458, upload-time = "2026-05-18T04:32:11.875Z" }, + { url = "https://files.pythonhosted.org/packages/d3/3d/4dd457062083ab1938e5dfd45032eb425cee2ac817287ca8ff4356183e5d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2", size = 464707, upload-time = "2026-05-18T04:30:43.492Z" }, + { url = "https://files.pythonhosted.org/packages/c6/71/ea8c57b128f5383de74d0c7d2d9c57ad7c9a65a930c451bd25d524b295b7/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9", size = 454663, upload-time = "2026-05-18T04:30:16.061Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/2e812bf938406d7db351f0703ddd3fc6c061cf30d96153a77bc79a943a44/watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa", size = 463537, upload-time = "2026-05-18T04:31:44.9Z" }, + { url = "https://files.pythonhosted.org/packages/86/56/d17a7f1dd1bc3035f1072694a551301272f1739c2d8e319c927cb9e29b38/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44", size = 629194, upload-time = "2026-05-18T04:31:14.141Z" }, + { url = "https://files.pythonhosted.org/packages/be/06/f1ff66bf5cae50aa4062779a0ecd0bbaf15e466195719074078947d9a17d/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72", size = 656194, upload-time = "2026-05-18T04:31:47.14Z" }, + { url = "https://files.pythonhosted.org/packages/e7/54/a9c7ea9a82a4ac65e7004c0a03920b5cdd2f9c3b678757d9cd425aa51d53/watchfiles-1.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b8c8358484d5fa12ef34f05b7f4168eaf1932f408725ff6d023c33ec17bd79d4", size = 400205, upload-time = "2026-05-18T04:32:05.153Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5d/c9ab3534374a4a67450696905d6ef16a04405448b8dc52bd752ae50423d4/watchfiles-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f04b092229ad2c50126dd3c922c8822e51e605993764a33058d4a791ab42281", size = 392508, upload-time = "2026-05-18T04:30:54.849Z" }, + { url = "https://files.pythonhosted.org/packages/26/ca/1ad30103535cf0cecd7b993e8d50edc5351b1820e38f2d22e3df58962feb/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a7ce236284f002a156f70add88efe5c70879cccbb658be0822c54b1306fc09d", size = 452448, upload-time = "2026-05-18T04:30:53.727Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/ceee2cdf2afbd715fa07758d39c9859513eae411b23196f7fd039e5feedd/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9909cc2b48468b575eefa944919e1fe8a36c5849d5c7c168f80a8c1db69398e", size = 459605, upload-time = "2026-05-18T04:30:23.312Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f6/421e30fd1cb3907a84ed92ab3f1983e37ba2dca015e9a894a048418417a2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a37faaed405c67e28e6be45a1fa4f206ef5a2860f27c237db9fa30704c38242", size = 490757, upload-time = "2026-05-18T04:30:47.358Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/55ed1b97ed08be7bba6f9a541cac15f2a858e1d74d2b07b6da70a82aab00/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9649193aa27bd9ff2e80ff29bfaa93085496c7a3a377592823cc58b77ee88add", size = 568672, upload-time = "2026-05-18T04:30:38.915Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cf/d8ae8a80dd7bafab395ea7681c10237311bbf34d37704a8c744e7cf31fc7/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e4ff8e37f99cf1da89e255e07c9c4b37c214038c4283707bdec308cb1b0ea1f", size = 464197, upload-time = "2026-05-18T04:30:09.914Z" }, + { url = "https://files.pythonhosted.org/packages/7c/8a/3076c496ca8dafe0e8cd03fcebdfc47be4b1174b4e5b24ff6e396e6b3af2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:054dc20fd2e3132b4c3883b4a00d72fd6e1f56fdaf89fccd12e8057d74cd74d7", size = 453181, upload-time = "2026-05-18T04:30:14.829Z" }, + { url = "https://files.pythonhosted.org/packages/e5/10/9745e17c98e7b8a86454df0a3c7b5686bd650383f1e9f26e4ebcbd6cc0c0/watchfiles-1.2.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e140ed30ebde76796b686e67c182cff10ea2fbab186fafd1560f74bb5a473a6e", size = 465109, upload-time = "2026-05-18T04:30:28.123Z" }, + { url = "https://files.pythonhosted.org/packages/8f/95/8ef4a95481d3e0cb52d62a06fa6e972e81424be2d9698b91a2fecca9904c/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:bb7e52ecf68ba46d22df23467b87cffeb2146908aa523ebfe803019618cfda06", size = 630653, upload-time = "2026-05-18T04:31:49.304Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e4/3b3bf36b0f829b50c6ebcb8d031583863c59f923d6a6af3d485e470d0fac/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:23282a321c8baf9b3a3c4afff673f9fe65eb7fdc2338d765ccad9d3d1916a5ba", size = 657838, upload-time = "2026-05-18T04:31:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/21/b1/6cbbb50c1f3002ab568777d44aa21206dfb8807a840990c4037523b51812/watchfiles-1.2.0-cp314-cp314-win32.whl", hash = "sha256:c0db965c5f79aa49fe672d297cf1febc5ad149b658594944f49a54a2b96270a7", size = 275108, upload-time = "2026-05-18T04:30:06.891Z" }, + { url = "https://files.pythonhosted.org/packages/92/45/190ce6db8dcb4536682cf75d3889ff1a27182a58cb519d343cb6d9ea63d8/watchfiles-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:71283b39fd17e5408eb123bd37aeecfd9d54c81fc184421943208aadb879d103", size = 288441, upload-time = "2026-05-18T04:32:12.901Z" }, + { url = "https://files.pythonhosted.org/packages/74/0d/3eae1c2313ab08378431d907c3f8095ecca00f3eda33111cf4f0f2591799/watchfiles-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:c5c19526f4e54a00f2666a6c0e9e40d582c09e865055ea7378bf0009aab857b3", size = 280684, upload-time = "2026-05-18T04:31:26.902Z" }, + { url = "https://files.pythonhosted.org/packages/b1/75/fb64e6c25d6b5ca636d03df34ffb1c6e9873303e76d27967e045f8df088f/watchfiles-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d73a585accffa5ae39c17264c36ec3166d2fad7000c780f5ef83b2722afb9dd2", size = 398857, upload-time = "2026-05-18T04:32:17.108Z" }, + { url = "https://files.pythonhosted.org/packages/73/4e/9f7adf01754cbf81843722ccfec169d8f26c69778281a302855cecd2ee08/watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae99b14c5f21e026e0e9d96f40e07d8570ebee6cafd9d8fc318354606daa7a28", size = 392413, upload-time = "2026-05-18T04:31:07.911Z" }, + { url = "https://files.pythonhosted.org/packages/47/c8/bec626bcc2d69f44b9acb24ce7d60ed7b16b73628eea747fcbd169d8edda/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429f3b105524a10b72c3a819b091c495d2811d419c1e1e8df773a5a5974f831", size = 452409, upload-time = "2026-05-18T04:31:20.142Z" }, + { url = "https://files.pythonhosted.org/packages/00/b7/b6362068e81e7c556d155a34c35d40ac3ef42d747b06d7f6e5bf58e359c2/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d818978d06062d9b22c4fab2ebe44cf5213d42dc8e62bda8c2760cfa2eeb33", size = 458827, upload-time = "2026-05-18T04:32:06.219Z" }, + { url = "https://files.pythonhosted.org/packages/67/f8/9a813fa42afb1e0b4625e75f0479826644d3ee8dc287e093799bc01f390c/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f732dc58b2dbe69e464ccf8fff7a03b0dd0be439da4c0720d3558527d3d6b4", size = 490104, upload-time = "2026-05-18T04:31:56.034Z" }, + { url = "https://files.pythonhosted.org/packages/2f/bf/27dfb6094ca4c9aad21298b5525b6c53cb36121ee454331d05161e58d130/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f200104103feb097de4cab8fe4f5dd18a2026934c7dea98c55a2f5fd6d5a33b", size = 571360, upload-time = "2026-05-18T04:31:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/fb/39/44a096d67270ea93df91d33877dbe91fbda3aa4f8ec2edf799d93eda8736/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ac26eefbf4af1741247d6fb68b11c49a25b2f7413fbd318a83a12aaa9cf666", size = 464644, upload-time = "2026-05-18T04:30:57.33Z" }, + { url = "https://files.pythonhosted.org/packages/0e/80/c7472203bad6268e3ef1ad260739704847898938ad7ea8b63a5131f46b50/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4997d4e4a55f0d02b6cde327322daf3a0400e5df6c6b15948994bf72497925", size = 454771, upload-time = "2026-05-18T04:30:48.736Z" }, + { url = "https://files.pythonhosted.org/packages/51/cf/3b10b268b4b7f0fc26e9debb5eef1998b515887840f444cd3ec80c688755/watchfiles-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4c887eba18b7945ac73067a8b4a66f21cd46c2539b2bc68588f7be6c7eb6d26b", size = 463494, upload-time = "2026-05-18T04:31:33.826Z" }, + { url = "https://files.pythonhosted.org/packages/3d/3e/a4302545cd589262a0dc7d140e86f7688eba3f9c72776c27f7e23b8864c4/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3416ff151bb6b5a8d8d11664974fbef4d9305b9b2957839ab5a270468fd8df30", size = 629383, upload-time = "2026-05-18T04:31:15.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/99/d5649df0a9a410d45b7c882304d0b790903ac9b6e8f2cfd12114e0c6b9f2/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0e831a271c035d89789cffc386b6aa1375f39f1cd25eb7ca0997e4970d152fc5", size = 656093, upload-time = "2026-05-18T04:31:58.707Z" }, + { url = "https://files.pythonhosted.org/packages/92/b9/362702539275019a54dd2e94511b31a9b89c5f9e6a21966de7eb692549fc/watchfiles-1.2.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:37a6721cdf3f65dbb13aa9503510ccb4451603ac837e44d265d7992a597e1374", size = 400109, upload-time = "2026-05-18T04:31:16.879Z" }, + { url = "https://files.pythonhosted.org/packages/8f/75/71d5ba62db781e5587bded1d944c675374bc4aa37ff33d5018d98e8b6538/watchfiles-1.2.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2b37d10b5a63bd4d87e18472d80fa525bd670586fae62e5dd580452764879b65", size = 392167, upload-time = "2026-05-18T04:31:28.058Z" }, + { url = "https://files.pythonhosted.org/packages/3c/01/c66dd95d0423fe30d31820e2d1d5bda773764131bbb6ac0cb1cf303ac328/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a105bc2283f67e8fbec74253ec2d94925de92ed72c0393f1206bf326b7b7b69", size = 452372, upload-time = "2026-05-18T04:31:00.836Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/2fe99557e72f85627c6a8eed50d889e8d101623e060a22ad75b875cb932d/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5327989a465505f05cfe06f04fa9d0c2fd5432bb243e10e6f012b1bdca3c8579", size = 459596, upload-time = "2026-05-18T04:31:34.96Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/d4acfa0023367428ed48351b3b9b267893037b6cadae55620c61c24bcfd4/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb47f183a8025b2aa18b546725c3657e542112ae9c0613a2af79b4fa8d04ad7", size = 490869, upload-time = "2026-05-18T04:31:59.923Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5f/3164cbdce06c9fb95c4f7b9e2f9760b5e2797af43a9ecc317ef42a23a278/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8520a4ab0e37f770afc34459c4f8f7019e153f9124dc101c15538365875d1ab2", size = 571641, upload-time = "2026-05-18T04:32:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/e6/85d3731c55e65cd7690f3f803d24c139588aaf863e4bf2148fe7a7fa1a19/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71cd71740ed2c15211ebb237ced4e39a1cdf6f80566e5fe95428da1626f4fde6", size = 464444, upload-time = "2026-05-18T04:30:34.298Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7d/562641012b8b09872742c3b8adf9629ec479fd78f8d68ae4a0c13da8add6/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f88af53d6ddaf72179ef613ddc905e6f4785f712b49b80b3bef9f3525e6194b4", size = 453593, upload-time = "2026-05-18T04:31:23.464Z" }, + { url = "https://files.pythonhosted.org/packages/56/fe/cb8ef3d6f929d14158fdaaad9925985b7310abc9384dcd4d82dd0016fb59/watchfiles-1.2.0-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:cee9d5efd929efdac5f7e58f72b3376f676b64050a91c5b99a7094c5b2317488", size = 465096, upload-time = "2026-05-18T04:31:30.384Z" }, + { url = "https://files.pythonhosted.org/packages/25/91/80908e835e100527a9267147b08c0eee1fa6ab0ffec15edc04d1d44885f7/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:b718bf356bbc15e559bd8ef41782b573b8ae0e3f177ab244b440568d7ea02cfb", size = 630638, upload-time = "2026-05-18T04:30:49.89Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/95ab2f256bb4af3cb2eb23b9317bda984ee6e0f11733a5c004a6c95b06e3/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:922c0e019fe68b3ae392965a766b02a71ba1168c932cebc3733cd52c5fe5b377", size = 657684, upload-time = "2026-05-18T04:31:32.027Z" }, ] [[package]] @@ -2162,86 +2379,65 @@ wheels = [ [[package]] name = "yarl" -version = "1.23.0" +version = "1.24.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/12/1e8f37460ea0f7eb59c221fdaf0ed75e7ac43e97f8093b9c6f411df50a78/yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8", size = 210798, upload-time = "2026-05-19T21:31:05.599Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" }, - { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" }, - { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" }, - { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" }, - { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" }, - { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" }, - { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" }, - { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" }, - { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" }, - { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" }, - { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" }, - { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" }, - { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" }, - { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" }, - { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" }, - { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" }, - { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" }, - { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" }, - { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" }, - { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" }, - { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" }, - { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" }, - { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" }, - { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" }, - { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" }, - { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" }, - { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" }, - { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" }, - { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" }, - { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" }, - { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" }, - { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" }, - { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" }, - { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" }, - { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" }, - { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" }, - { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" }, - { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" }, - { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" }, - { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" }, - { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" }, - { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" }, - { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" }, - { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" }, - { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" }, - { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" }, - { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" }, - { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" }, - { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" }, - { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" }, - { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" }, - { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" }, - { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" }, - { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" }, - { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/fcf0ce677f17e5c471c06311dd25964be38a4c586993632910d2e75278bc/yarl-1.24.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:491ac9141decf49ee8030199e1ee251cdff0e131f25678817ff6aa5f837a3536", size = 128978, upload-time = "2026-05-19T21:29:23.83Z" }, + { url = "https://files.pythonhosted.org/packages/d3/58/8e63299bb71ed61a834121d9d3fe6c9fcf2a6a5d09754ff4f20f2d20baf5/yarl-1.24.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e89418f65eda18f99030386305bd44d7d504e328a7945db1ead514fbe03a0607", size = 91733, upload-time = "2026-05-19T21:29:25.375Z" }, + { url = "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cdfcce633b4a4bb8281913c57fcafd4b5933fbc19111a5e3930bbd299d6102f1", size = 91113, upload-time = "2026-05-19T21:29:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/1b/66/b63fff7b71211e866624b21432d5943cbb633eb0c2872d9ee3070648f22c/yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:863297ddede92ee49024e9a9b11ecb59f310ca85b60d8537f56bed9bbb5b1986", size = 103899, upload-time = "2026-05-19T21:29:28.842Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ac/ba1974b8533909636f7733fe86cf677e3619527c3c2fa913e0ea89c48757/yarl-1.24.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:374423f70754a2c96942ede36a29d37dc6b0cb8f92f8d009ddf3ed78d3da5488", size = 97862, upload-time = "2026-05-19T21:29:31.086Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a5/123ac993b5c2ba6f554a140305620cb8f150fa543711bbc49be3ec0a65a4/yarl-1.24.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33a29b5d00ccbf3219bb3e351d7875739c19481e030779f48cc46a7a71681a9b", size = 111060, upload-time = "2026-05-19T21:29:32.657Z" }, + { url = "https://files.pythonhosted.org/packages/23/37/c472d3af3509688392134a88a825276770a187f1daa4de3f6dc0a327a751/yarl-1.24.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a9532c57211730c515341af11fef6e9b61d157487272a096d0c04da445642592", size = 110613, upload-time = "2026-05-19T21:29:34.379Z" }, + { url = "https://files.pythonhosted.org/packages/df/88/09c28dad91e662ccfaa1b78f1c57badde74fc9d0b23e74aef644750ecd73/yarl-1.24.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91e72cf093fd833483a97ee648e0c053c7c629f51ff4a0e7edd84f806b0c5617", size = 107012, upload-time = "2026-05-19T21:29:36.216Z" }, + { url = "https://files.pythonhosted.org/packages/07/ab/9d4f69d571a94f4d112fa7e2e007200f5a54d319f58c82ac7b7baa61f5c6/yarl-1.24.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b3177bc0a768ef3bacceb4f272632990b7bea352f1b2f1eee9d6d6ff16516f92", size = 105887, upload-time = "2026-05-19T21:29:38.746Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9a/000b2b66c0d772a499fc531d21dab92dfeb73b640a12eed6ba89f49bb2d0/yarl-1.24.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e196952aacaf3b232e265ff02980b64d483dc0972bd49bcb061171ff22ac203a", size = 103620, upload-time = "2026-05-19T21:29:40.368Z" }, + { url = "https://files.pythonhosted.org/packages/41/7c/7c1050f73450fbdaa3f0c72017059f00ce5e13366692f3dba25275a1083d/yarl-1.24.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:204e7a61ce99919c0de1bf904ab5d7aa188a129ea8f690a8f76cfb6e2844dc44", size = 100599, upload-time = "2026-05-19T21:29:42.66Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b1/29e5756b3926705f5f6089bd5b9f50a56eaac550da6e260bf713ead44d04/yarl-1.24.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b156914620f0b9d78dc1adb3751141daee561cfec796088abb89ed49d220f1a", size = 110604, upload-time = "2026-05-19T21:29:44.632Z" }, + { url = "https://files.pythonhosted.org/packages/a3/4b/8415bc96e9b150cde942fbac9a8182985e58f40ce5c54c34ed015407d3ee/yarl-1.24.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8372a2b976cf70654b2be6619ab6068acabb35f724c0fda7b277fbf53d66a5cf", size = 105161, upload-time = "2026-05-19T21:29:46.755Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d4/cde059abfa229553b7298a2eadde2752e723d50aeedaef86ce59da2718ee/yarl-1.24.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f9a1e9b622ca284143aab5d885848686dcd85453bb1ca9abcdb7503e64dc0056", size = 110619, upload-time = "2026-05-19T21:29:48.972Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2c/d6a6c9a61549f7b6c7e6dc6937d195bcf069582b47b7200dcd0e7b256acf/yarl-1.24.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:810e19b685c8c3c5862f6a38160a1f4e4c0916c9390024ec347b6157a45a0992", size = 107362, upload-time = "2026-05-19T21:29:51Z" }, + { url = "https://files.pythonhosted.org/packages/92/dd/3ae5fe417e9d1c353a548553326eb9935e76b6b727161563b424cc296df3/yarl-1.24.2-cp313-cp313-win_amd64.whl", hash = "sha256:7d37fb7c38f2b6edab0f845c4f85148d4c44204f52bc127021bd2bc9fdbf1656", size = 92667, upload-time = "2026-05-19T21:29:52.743Z" }, + { url = "https://files.pythonhosted.org/packages/10/cc/a7beb239f78f27fca1b053c8e8595e4179c02e62249b4687ec218c370c50/yarl-1.24.2-cp313-cp313-win_arm64.whl", hash = "sha256:1e831894be7c2954240e49791fa4b50c05a0dc881de2552cfe3ffd8631c7f461", size = 87069, upload-time = "2026-05-19T21:29:54.442Z" }, + { url = "https://files.pythonhosted.org/packages/40/0e/e08087695fc12789263821c5dc0f8dc52b5b17efd0887cacf419f8a43ba3/yarl-1.24.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2", size = 129670, upload-time = "2026-05-19T21:29:56.631Z" }, + { url = "https://files.pythonhosted.org/packages/3a/98/ab4b5ed1b1b5cd973c8a3eb994c3a6aefb6ce6d399e21bb5f0316c33815c/yarl-1.24.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630", size = 91916, upload-time = "2026-05-19T21:29:58.645Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b1/5297bb6a7df4782f7605bffc43b31f5044070935fbbcaa6c705a07e6ac65/yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8", size = 91625, upload-time = "2026-05-19T21:30:00.412Z" }, + { url = "https://files.pythonhosted.org/packages/02/a7/45baabfff76829264e623b185cff0c340d7e11bf3e1cd9ea37e7d17934bd/yarl-1.24.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14", size = 104574, upload-time = "2026-05-19T21:30:02.544Z" }, + { url = "https://files.pythonhosted.org/packages/f3/40/3a5ab144d3d650ca37d4f4b57e56169be8af3ca34c448793e064b30baaed/yarl-1.24.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535", size = 97534, upload-time = "2026-05-19T21:30:04.319Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b5/5658fef3681fb5776b4513b052bec750009f47b3a592251c705d75375798/yarl-1.24.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14", size = 111481, upload-time = "2026-05-19T21:30:05.988Z" }, + { url = "https://files.pythonhosted.org/packages/4c/06/fdcd7dde037f00866dce123ed4ba23dba94beb56fc4cf561668d27be37f2/yarl-1.24.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3", size = 111529, upload-time = "2026-05-19T21:30:07.738Z" }, + { url = "https://files.pythonhosted.org/packages/c2/53/d81269aaafccea0d33396c03035de997b743f11e648e6e27a0df99c72980/yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208", size = 107338, upload-time = "2026-05-19T21:30:09.713Z" }, + { url = "https://files.pythonhosted.org/packages/ae/04/23049463f729bd899df203a7960505a75333edd499cda8aa1d5a82b64df5/yarl-1.24.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50", size = 106147, upload-time = "2026-05-19T21:30:11.365Z" }, + { url = "https://files.pythonhosted.org/packages/14/18/04a4b5830b43ed5e4c5015b40e9f6241ad91487d71611061b4e111d6ac80/yarl-1.24.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd", size = 104272, upload-time = "2026-05-19T21:30:12.978Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f7/8cffdf319aee7a7c1dbd07b61d91c3e3fda460c7a93b5f93e445f3806c4c/yarl-1.24.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67", size = 99962, upload-time = "2026-05-19T21:30:15.001Z" }, + { url = "https://files.pythonhosted.org/packages/d7/39/b3cce3b7dbef64ac700ad4cea156a207d01bede0f507587616c364b5468e/yarl-1.24.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1", size = 111063, upload-time = "2026-05-19T21:30:16.683Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ea/100818505e7ebf165c7242ff17fdf7d9fee79e27234aeca871c1082920d7/yarl-1.24.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1", size = 105438, upload-time = "2026-05-19T21:30:18.769Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d2/e075a0b32aa6625087de9e653087df0759fed5de4a435fef594181102a77/yarl-1.24.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b", size = 111458, upload-time = "2026-05-19T21:30:21.024Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5c/ceea7ba98b65c8eb8d947fdc52f9bedfcd43c6a57c9e3c90c17be8f324a3/yarl-1.24.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8", size = 107589, upload-time = "2026-05-19T21:30:23.412Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d9/5582d57e2b2db9b85eb6663a22efdd78e08805f3f5389566e9fcad254d1b/yarl-1.24.2-cp314-cp314-win_amd64.whl", hash = "sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0", size = 94424, upload-time = "2026-05-19T21:30:25.425Z" }, + { url = "https://files.pythonhosted.org/packages/92/10/7dc07a0e22806a9280f42a57361395506e800c64e22737cd7b0886feab42/yarl-1.24.2-cp314-cp314-win_arm64.whl", hash = "sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57", size = 88690, upload-time = "2026-05-19T21:30:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/9e/13/d5b8e2c8667db955bcb3de233f18798fefe7edf1d7429c2c9d4f9c401114/yarl-1.24.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b", size = 136248, upload-time = "2026-05-19T21:30:29.297Z" }, + { url = "https://files.pythonhosted.org/packages/de/46/a4a97c05c9c9b8fd266bb2a0df12992c7fbd02391eb9640583411b6dab32/yarl-1.24.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761", size = 95084, upload-time = "2026-05-19T21:30:31.031Z" }, + { url = "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8", size = 95272, upload-time = "2026-05-19T21:30:33.062Z" }, + { url = "https://files.pythonhosted.org/packages/fe/16/e69d4aa244aef45235ddfebc0e04036a6829842bc5a6a795aedc6c998d23/yarl-1.24.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed", size = 101497, upload-time = "2026-05-19T21:30:34.842Z" }, + { url = "https://files.pythonhosted.org/packages/15/94/c07107715d621076863ee88b3ddf183fa5e9d4aba5769623c9979828410a/yarl-1.24.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543", size = 94002, upload-time = "2026-05-19T21:30:37.724Z" }, + { url = "https://files.pythonhosted.org/packages/a9/35/fc1bbdd895b5e4010b8fdd037f7ed3aa289d3863e08231b30231ca9a0815/yarl-1.24.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0", size = 106524, upload-time = "2026-05-19T21:30:40.196Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/32b66d0a4ba47c296cf86d03e2c67bff58399fe6d6d84d5205c04c66cc6d/yarl-1.24.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024", size = 106165, upload-time = "2026-05-19T21:30:41.888Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/37cb5ff50c5e825d4d38e81bb04d1b7e96bf960f7ab89f9850b162f3f114/yarl-1.24.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf", size = 103010, upload-time = "2026-05-19T21:30:43.985Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/4597912315096f7bb359e46e13bf8b60994fcbb2db29b804c0902ef4eff5/yarl-1.24.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc", size = 101128, upload-time = "2026-05-19T21:30:46.291Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d5/c8e86e120521e646013d02a8e3b8884392e28494be8f392366e50d208efc/yarl-1.24.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb", size = 101382, upload-time = "2026-05-19T21:30:48.085Z" }, + { url = "https://files.pythonhosted.org/packages/fa/98/70b229236118f89dbeb739b76f10225bbf53b5497725502594c9a01d699a/yarl-1.24.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420", size = 95964, upload-time = "2026-05-19T21:30:49.785Z" }, + { url = "https://files.pythonhosted.org/packages/87/f8/56c386981e3c8648d279fdef2397ffec577e8320fd5649745e34d54faeb7/yarl-1.24.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f", size = 106204, upload-time = "2026-05-19T21:30:51.862Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1e/765afe97811ca35933e2a7de70ac57b1997ea2e4ee895719ee7a231fb7e5/yarl-1.24.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa", size = 101510, upload-time = "2026-05-19T21:30:53.62Z" }, + { url = "https://files.pythonhosted.org/packages/ee/78/393913f4b9039e1edd09ae8a9bbb9d539be909a8abf6d8a2084585bed4b7/yarl-1.24.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe", size = 105584, upload-time = "2026-05-19T21:30:55.962Z" }, + { url = "https://files.pythonhosted.org/packages/78/87/deb17b7049bbe74ea11a713b86f8f27800cc1c8648b0b797243ebb4830ba/yarl-1.24.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd", size = 103410, upload-time = "2026-05-19T21:30:57.962Z" }, + { url = "https://files.pythonhosted.org/packages/8f/be/f9f7594e23b5b93affff0318e4593c1920331bcaefda326cabcad94296a1/yarl-1.24.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215", size = 102980, upload-time = "2026-05-19T21:30:59.735Z" }, + { url = "https://files.pythonhosted.org/packages/65/a4/ba80dccd3593ff1f01051a818694d07b58cb8232677ee9a22a5a1f93a9fc/yarl-1.24.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d", size = 91219, upload-time = "2026-05-19T21:31:01.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/4d/4b880086bd0d3e034d25647be1d830afc3e3f610e98c4ab3490af6b1b6d5/yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9", size = 53576, upload-time = "2026-05-19T21:31:03.909Z" }, ] diff --git a/scripts/add_new_material_categories.sql b/scripts/add_new_material_categories.sql deleted file mode 100644 index a3bbf40..0000000 --- a/scripts/add_new_material_categories.sql +++ /dev/null @@ -1,127 +0,0 @@ --- 新增素材分类 SQL(2025-06-03) --- 文件1:新房装修流程(4 个分类)+ 文件2:装备材料选择(44 个分类) - -DO $$ -DECLARE - l1_cailiao_id bigint; - l2_fengchuang_id bigint; - l2_zhanshi_id bigint; -BEGIN - -- ====================== 文件1:新房装修流程 ====================== - - -- 二级:封窗镜(拆改改造类下,sort_order=4) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('chaigai-fengchuang', '封窗镜', 46, 2, 4, 'active', NOW(), NOW()) - RETURNING id INTO l2_fengchuang_id; - - -- 三级:封窗施工-封窗镜 - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('chaigai-fengchuang-fcsg', '封窗施工-封窗镜', l2_fengchuang_id, 3, 1, 'active', NOW(), NOW()); - - -- 三级:装烟机灶具-主材安装镜(parent_id=189 主材安装镜,sort_order=9) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('anzhuang-zhucai-zyjzj', '装烟机灶具-主材安装镜', 189, 3, 9, 'active', NOW(), NOW()); - - -- 三级:家具进场摆放就位-软装进场镜(parent_id=219 软装进场镜,sort_order=2) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('ruanzhuang-ruanchang-jjjcbfjw', '家具进场摆放就位-软装进场镜', 219, 3, 2, 'active', NOW(), NOW()); - - -- ====================== 文件2:装备材料选择 ====================== - - -- 一级:装修材料选择(sort_order=90) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao', '装修材料选择', NULL, 1, 90, 'active', NOW(), NOW()) - RETURNING id INTO l1_cailiao_id; - - -- 二级:材料展示 - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi', '材料展示', l1_cailiao_id, 2, 1, 'active', NOW(), NOW()) - RETURNING id INTO l2_zhanshi_id; - - -- 三级:XX买谁家 + 品牌组合(42 个) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-bxmsj', '冰箱买谁家', l2_zhanshi_id, 3, 1, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dsmsj', '电视买谁家', l2_zhanshi_id, 3, 2, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-hsj', '花洒哪家好', l2_zhanshi_id, 3, 3, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dxmsj', '电线买谁家', l2_zhanshi_id, 3, 4, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-yjj', '烟机哪家好', l2_zhanshi_id, 3, 5, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-rjqmsj', '乳胶漆买谁家', l2_zhanshi_id, 3, 6, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-kgczmsj', '开关插座买谁家', l2_zhanshi_id, 3, 7, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-czj', '瓷砖哪家好', l2_zhanshi_id, 3, 8, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-sgmsj', '水管买谁家', l2_zhanshi_id, 3, 9, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-bcxsj', '板材选谁家', l2_zhanshi_id, 3, 10, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-fsmsj', '防水买谁家', l2_zhanshi_id, 3, 11, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-ddxsj', '吊顶选谁家', l2_zhanshi_id, 3, 12, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dbj', '地板哪家好', l2_zhanshi_id, 3, 13, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-nzfj', '腻子粉哪家好', l2_zhanshi_id, 3, 14, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dlsj', '地漏谁家好', l2_zhanshi_id, 3, 15, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-jzsgsj', '家装水管谁家好', l2_zhanshi_id, 3, 16, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-jzsnsj', '家装水泥谁家好', l2_zhanshi_id, 3, 17, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-cwwjsj', '厨卫五金谁家好', l2_zhanshi_id, 3, 18, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-sgbsj', '石膏板谁家好', l2_zhanshi_id, 3, 19, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-czjsj', '瓷砖胶谁家好', l2_zhanshi_id, 3, 20, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-bljsj', '玻璃胶谁家好', l2_zhanshi_id, 3, 21, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-hemdksd', '海尔美的卡萨帝', l2_zhanshi_id, 3, 22, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-snhxtcl', '索尼海信TCL', l2_zhanshi_id, 3, 23, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-jmhjjp', '九牧恒洁箭牌', l2_zhanshi_id, 3, 24, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-ydbsxm', '远东宝胜熊猫', l2_zhanshi_id, 3, 25, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-ftlbhd', '方太老板华帝', l2_zhanshi_id, 3, 26, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-lbsksdls', '立邦三棵树多乐士', l2_zhanshi_id, 3, 27, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-gnsndxmz', '公牛施耐德西门子', l2_zhanshi_id, 3, 28, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dpgzmkbl', '东鹏冠珠马可波罗', l2_zhanshi_id, 3, 29, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-rfwxbl', '日丰伟星保利', l2_zhanshi_id, 3, 30, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-whagtbb', '万华爱格兔宝宝', l2_zhanshi_id, 3, 31, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-lbdgdfyh', '立邦德高东方雨虹', l2_zhanshi_id, 3, 32, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-apybfsl', '奥普友邦法狮龙', l2_zhanshi_id, 3, 33, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-sxsydzr', '圣象世友大自然', l2_zhanshi_id, 3, 34, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-lbmcsgb', '立邦美巢圣戈邦', l2_zhanshi_id, 3, 35, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-jmjpqst', '九牧箭牌潜水艇', l2_zhanshi_id, 3, 36, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-jnwxrf', '金牛伟星日丰', l2_zhanshi_id, 3, 37, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-hlhszl', '海螺红狮中联', l2_zhanshi_id, 3, 38, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-kljmhsgy', '科勒九牧汉斯格雅', l2_zhanshi_id, 3, 39, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-lptsknf', '龙牌泰山可耐福', l2_zhanshi_id, 3, 40, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-dgxkm', '德高西卡马贝', l2_zhanshi_id, 3, 41, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('cailiao-zhanshi-wkxkbd', '瓦克西卡百得', l2_zhanshi_id, 3, 42, 'active', NOW(), NOW()); - -END $$; diff --git a/scripts/admin-ops.sql b/scripts/admin-ops.sql deleted file mode 100644 index 05788d1..0000000 --- a/scripts/admin-ops.sql +++ /dev/null @@ -1,405 +0,0 @@ --- ============================================================ --- 美家卡智影 - 后台运维 SQL 脚本 --- 适用场景:暂无管理后台,直接操作数据库 --- 注意:所有操作应在事务中执行,操作前请备份数据 --- ============================================================ - --- ----------------------------------------------------------- --- 一、新增用户(支持同时赠送初始积分) --- ----------------------------------------------------------- --- 用法:修改下方变量后执行 - -DO $$ -DECLARE - v_mobile TEXT := '13559213930'; -- ← 修改:手机号 - v_nickname TEXT := '俊宏'; -- ← 修改:昵称(可为空) - v_source TEXT := 'manual'; -- ← 修改:注册来源:manual / invite / promotion - v_invited_by UUID := NULL; -- ← 修改:邀请人 user_id(没有则留 NULL) - v_gift_points INT := 2000; -- ← 修改:赠送初始积分(0 表示不赠送) - v_gift_days INT := 365; -- ← 修改:赠送积分有效期(天) - v_user_id UUID; - v_batch_id BIGINT; - v_now TIMESTAMPTZ := NOW(); -BEGIN - -- 1. 插入用户 - INSERT INTO mjk_users ( - id, mobile, password_hash, status, nickname, - avatar_url, source, invited_by, - last_login_at, last_login_ip, deleted_at, extra, - created_at, updated_at - ) VALUES ( - gen_random_uuid(), - v_mobile, - NULL, -- 密码哈希(未设置密码) - 'active', - v_nickname, - NULL, - v_source, - v_invited_by, - NULL, NULL, NULL, - '{}'::JSONB, - v_now, v_now - ) - RETURNING id INTO v_user_id; - - -- 2. 初始化积分汇总(余额为 0) - INSERT INTO mjk_user_points ( - user_id, balance, total_recharged, total_consumed, total_expired, - created_at, updated_at - ) VALUES ( - v_user_id, 0, 0, 0, 0, - v_now, v_now - ); - - -- 3. 如有赠送积分,创建批次 + 流水 + 更新余额 - IF v_gift_points > 0 THEN - -- 3.1 插入积分批次 - INSERT INTO mjk_point_batches ( - user_id, amount, remaining, expired_at, source, - created_at, updated_at - ) VALUES ( - v_user_id, - v_gift_points, - v_gift_points, - v_now + (v_gift_days || ' days')::INTERVAL, - 'gift', - v_now, v_now - ) - RETURNING id INTO v_batch_id; - - -- 3.2 插入积分流水 - INSERT INTO mjk_point_transactions ( - user_id, type, amount, - balance_before, balance_after, - source_type, source_id, batch_id, - duration, category, description, - created_at, updated_at - ) VALUES ( - v_user_id, - 'recharge', - v_gift_points, - 0, -- 变动前余额 - v_gift_points, -- 变动后余额 - 'manual_gift', - v_batch_id::TEXT, - v_batch_id, - NULL, - '充值', - '新用户注册赠送积分', - v_now, v_now - ); - - -- 3.3 更新用户积分汇总 - UPDATE mjk_user_points - SET balance = v_gift_points, - total_recharged = v_gift_points, - updated_at = v_now - WHERE user_id = v_user_id; - END IF; - - RAISE NOTICE '用户创建成功,user_id = %', v_user_id; -END $$; - - --- ----------------------------------------------------------- --- 二、积分赠送(给已有用户赠送积分) --- ----------------------------------------------------------- --- 用法:修改下方变量后执行 - -DO $$ -DECLARE - v_mobile TEXT := '18750556093'; -- ← 修改:目标用户手机号 - v_gift_points INT := 5000; -- ← 修改:赠送积分数量 - v_gift_days INT := 180; -- ← 修改:有效期(天) - v_reason TEXT := '运营活动赠送'; -- ← 修改:赠送原因(写入流水描述) - v_user_id UUID; - v_batch_id BIGINT; - v_balance_before INT; - v_now TIMESTAMPTZ := NOW(); -BEGIN - -- 1. 查找用户 - SELECT id INTO v_user_id - FROM mjk_users - WHERE mobile = v_mobile - AND status = 'active' - AND deleted_at IS NULL; - - IF v_user_id IS NULL THEN - RAISE EXCEPTION '用户不存在或已注销:mobile = %', v_mobile; - END IF; - - -- 2. 获取当前余额 - SELECT balance INTO v_balance_before - FROM mjk_user_points - WHERE user_id = v_user_id; - - IF v_balance_before IS NULL THEN - -- 如果没有积分记录,先初始化 - INSERT INTO mjk_user_points ( - user_id, balance, total_recharged, total_consumed, total_expired, - created_at, updated_at - ) VALUES ( - v_user_id, 0, 0, 0, 0, - v_now, v_now - ); - v_balance_before := 0; - END IF; - - -- 3. 插入积分批次 - INSERT INTO mjk_point_batches ( - user_id, amount, remaining, expired_at, source, - created_at, updated_at - ) VALUES ( - v_user_id, - v_gift_points, - v_gift_points, - v_now + (v_gift_days || ' days')::INTERVAL, - 'gift', - v_now, v_now - ) - RETURNING id INTO v_batch_id; - - -- 4. 插入积分流水 - INSERT INTO mjk_point_transactions ( - user_id, type, amount, - balance_before, balance_after, - source_type, source_id, batch_id, - duration, category, description, - created_at, updated_at - ) VALUES ( - v_user_id, - 'recharge', - v_gift_points, - v_balance_before, - v_balance_before + v_gift_points, - 'manual_gift', - v_batch_id::TEXT, - v_batch_id, - NULL, - '充值', - v_reason, - v_now, v_now - ); - - -- 5. 更新用户积分汇总 - UPDATE mjk_user_points - SET balance = balance + v_gift_points, - total_recharged = total_recharged + v_gift_points, - updated_at = v_now - WHERE user_id = v_user_id; - - RAISE NOTICE '已向用户 % 赠送 % 积分,当前余额 = %', - v_mobile, v_gift_points, v_balance_before + v_gift_points; -END $$; - - --- ----------------------------------------------------------- --- 三、积分补偿(给用户补偿积分,source = compensation) --- ----------------------------------------------------------- --- 用法:修改下方变量后执行 - -DO $$ -DECLARE - v_mobile TEXT := '13800138000'; -- ← 修改:目标用户手机号 - v_comp_points INT := 200; -- ← 修改:补偿积分数量 - v_comp_days INT := 365; -- ← 修改:有效期(天,建议给长一点) - v_reason TEXT := '系统故障补偿'; -- ← 修改:补偿原因 - v_user_id UUID; - v_batch_id BIGINT; - v_balance_before INT; - v_now TIMESTAMPTZ := NOW(); -BEGIN - -- 1. 查找用户 - SELECT id INTO v_user_id - FROM mjk_users - WHERE mobile = v_mobile - AND status = 'active' - AND deleted_at IS NULL; - - IF v_user_id IS NULL THEN - RAISE EXCEPTION '用户不存在或已注销:mobile = %', v_mobile; - END IF; - - -- 2. 获取当前余额 - SELECT balance INTO v_balance_before - FROM mjk_user_points - WHERE user_id = v_user_id; - - IF v_balance_before IS NULL THEN - INSERT INTO mjk_user_points ( - user_id, balance, total_recharged, total_consumed, total_expired, - created_at, updated_at - ) VALUES ( - v_user_id, 0, 0, 0, 0, - v_now, v_now - ); - v_balance_before := 0; - END IF; - - -- 3. 插入积分批次(source = compensation) - INSERT INTO mjk_point_batches ( - user_id, amount, remaining, expired_at, source, - created_at, updated_at - ) VALUES ( - v_user_id, - v_comp_points, - v_comp_points, - v_now + (v_comp_days || ' days')::INTERVAL, - 'compensation', - v_now, v_now - ) - RETURNING id INTO v_batch_id; - - -- 4. 插入积分流水 - INSERT INTO mjk_point_transactions ( - user_id, type, amount, - balance_before, balance_after, - source_type, source_id, batch_id, - duration, category, description, - created_at, updated_at - ) VALUES ( - v_user_id, - 'recharge', - v_comp_points, - v_balance_before, - v_balance_before + v_comp_points, - 'manual_compensation', - v_batch_id::TEXT, - v_batch_id, - NULL, - '补偿', - v_reason, - v_now, v_now - ); - - -- 5. 更新用户积分汇总 - UPDATE mjk_user_points - SET balance = balance + v_comp_points, - total_recharged = total_recharged + v_comp_points, - updated_at = v_now - WHERE user_id = v_user_id; - - RAISE NOTICE '已向用户 % 补偿 % 积分,当前余额 = %', - v_mobile, v_comp_points, v_balance_before + v_comp_points; -END $$; - - --- ----------------------------------------------------------- --- 四、批量积分补偿(给多个用户同时补偿) --- ----------------------------------------------------------- --- 用法:将要补偿的手机号填入临时表,然后执行 - --- 步骤 1:创建临时补偿名单(手机号 + 补偿数量 + 原因) --- DROP TABLE IF EXISTS _temp_compensation_list; -CREATE TEMP TABLE IF NOT EXISTS _temp_compensation_list ( - mobile TEXT PRIMARY KEY, - comp_points INT NOT NULL, - reason TEXT NOT NULL DEFAULT '批量补偿' -); - --- 步骤 2:插入要补偿的用户(每次执行前清空并重新插入) -TRUNCATE _temp_compensation_list; -INSERT INTO _temp_compensation_list (mobile, comp_points, reason) VALUES - ('13800138000', 100, '活动补偿'), - ('13800138001', 200, '活动补偿'), - ('13800138002', 100, '活动补偿'); - --- 步骤 3:执行批量补偿 -DO $$ -DECLARE - v_rec RECORD; - v_user_id UUID; - v_batch_id BIGINT; - v_balance_before INT; - v_now TIMESTAMPTZ := NOW(); - v_comp_days INT := 365; - v_success_cnt INT := 0; - v_fail_cnt INT := 0; -BEGIN - FOR v_rec IN SELECT * FROM _temp_compensation_list LOOP - BEGIN - -- 查找用户 - SELECT id INTO v_user_id - FROM mjk_users - WHERE mobile = v_rec.mobile - AND status = 'active' - AND deleted_at IS NULL; - - IF v_user_id IS NULL THEN - RAISE WARNING '用户不存在:%', v_rec.mobile; - v_fail_cnt := v_fail_cnt + 1; - CONTINUE; - END IF; - - -- 获取当前余额 - SELECT balance INTO v_balance_before - FROM mjk_user_points - WHERE user_id = v_user_id; - - IF v_balance_before IS NULL THEN - INSERT INTO mjk_user_points ( - user_id, balance, total_recharged, total_consumed, total_expired, - created_at, updated_at - ) VALUES ( - v_user_id, 0, 0, 0, 0, - v_now, v_now - ); - v_balance_before := 0; - END IF; - - -- 插入批次 - INSERT INTO mjk_point_batches ( - user_id, amount, remaining, expired_at, source, - created_at, updated_at - ) VALUES ( - v_user_id, - v_rec.comp_points, - v_rec.comp_points, - v_now + (v_comp_days || ' days')::INTERVAL, - 'compensation', - v_now, v_now - ) - RETURNING id INTO v_batch_id; - - -- 插入流水 - INSERT INTO mjk_point_transactions ( - user_id, type, amount, - balance_before, balance_after, - source_type, source_id, batch_id, - duration, category, description, - created_at, updated_at - ) VALUES ( - v_user_id, - 'recharge', - v_rec.comp_points, - v_balance_before, - v_balance_before + v_rec.comp_points, - 'batch_compensation', - v_batch_id::TEXT, - v_batch_id, - NULL, - '补偿', - v_rec.reason, - v_now, v_now - ); - - -- 更新汇总 - UPDATE mjk_user_points - SET balance = balance + v_rec.comp_points, - total_recharged = total_recharged + v_rec.comp_points, - updated_at = v_now - WHERE user_id = v_user_id; - - v_success_cnt := v_success_cnt + 1; - - EXCEPTION WHEN OTHERS THEN - RAISE WARNING '补偿失败 %: %', v_rec.mobile, SQLERRM; - v_fail_cnt := v_fail_cnt + 1; - END; - END LOOP; - - RAISE NOTICE '批量补偿完成:成功 % 人,失败 % 人', v_success_cnt, v_fail_cnt; -END $$; - --- 清理临时表 --- DROP TABLE IF EXISTS _temp_compensation_list; diff --git a/scripts/batch_upload_qiniu.py b/scripts/batch_upload_qiniu.py deleted file mode 100644 index 61bf2a2..0000000 --- a/scripts/batch_upload_qiniu.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -import sys -from pathlib import Path -from dotenv import load_dotenv -from qiniu import Auth, put_file - -# 加载环境变量 -env_path = Path(__file__).resolve().parent.parent / 'python-api' / '.env' -load_dotenv(env_path) - -access_key = os.getenv('QINIU_ACCESS_KEY') -secret_key = os.getenv('QINIU_SECRET_KEY') -bucket = os.getenv('QINIU_VIDEO_BUCKET', 'media-liche') -domain = os.getenv('QINIU_VIDEO_DOMAIN', 'media.liche.cn') - -if not access_key or not secret_key: - print("错误: 未找到七牛云凭证,请检查 .env 文件") - sys.exit(1) - -q = Auth(access_key, secret_key) -src_dir = Path('/Users/0fun/Downloads/新增素材6.2') - -total = 0 -success = 0 -failed = 0 - -files = sorted([p for p in src_dir.rglob('*.mp4') if not p.name.startswith('._') and '.DS_Store' not in str(p)]) - -print(f"发现 {len(files)} 个 MP4 文件,开始上传...\n") - -for mp4_path in files: - total += 1 - key = f"meijiaka-zy/materials/{mp4_path.name}" - - try: - token = q.upload_token(bucket, key, 3600) - ret, info = put_file(token, key, str(mp4_path)) - if ret is not None: - url = f"https://{domain}/{key}" - print(f"✅ [{total}/{len(files)}] {mp4_path.name}") - success += 1 - else: - print(f"❌ [{total}/{len(files)}] {mp4_path.name} → 失败: {info}") - failed += 1 - except Exception as e: - print(f"❌ [{total}/{len(files)}] {mp4_path.name} → 异常: {e}") - failed += 1 - -print(f"\n{'=' * 50}") -print(f"总计: {total}, 成功: {success}, 失败: {failed}") diff --git a/scripts/bump-version.py b/scripts/bump-version.py deleted file mode 100644 index 78d7460..0000000 --- a/scripts/bump-version.py +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env python3 -"""统一版本号管理脚本。 - -用法: - python scripts/bump-version.py # 读取 VERSION 文件并同步到所有配置 - python scripts/bump-version.py 1.5.15 # 更新 VERSION 并同步(同时打 Git tag) - -覆盖文件: - - VERSION - - AGENTS.md - - tauri-app/AGENTS.md - - tauri-app/package.json - - tauri-app/src-tauri/Cargo.toml - - tauri-app/src-tauri/tauri.conf.json - - tauri-app/src-tauri/Cargo.lock - - tauri-app/package-lock.json - - tauri-app/src/store/authStore.ts - - python-api/pyproject.toml - - python-api/uv.lock - - python-api/app/config.py - - python-api/.env.example -""" - -import json -import re -import subprocess -import sys -from pathlib import Path - -ROOT = Path(__file__).parent.parent -VERSION_FILE = ROOT / "VERSION" - - -def read_version() -> str: - return VERSION_FILE.read_text().strip() - - -def write_version(version: str) -> None: - VERSION_FILE.write_text(version + "\n") - - -def bump_agents_md(path: Path, version: str) -> None: - content = path.read_text() - content = re.sub( - r'\*\*版本\*\*: `[^`]+`', - f'**版本**: `{version}`', - content, - ) - path.write_text(content) - - -def bump_cargo_toml(version: str) -> None: - path = ROOT / "tauri-app" / "src-tauri" / "Cargo.toml" - content = path.read_text() - content = re.sub( - r'^version = "[^"]+"', - f'version = "{version}"', - content, - flags=re.MULTILINE, - ) - path.write_text(content) - - -def bump_cargo_lock(version: str) -> None: - path = ROOT / "tauri-app" / "src-tauri" / "Cargo.lock" - content = path.read_text() - # Cargo.lock 中 tauri-app 包的版本行 - content = re.sub( - r'(\[\[package\]\]\nname = "tauri-app"\nversion = ")([^"]+)(")', - rf'\g<1>{version}\g<3>', - content, - ) - path.write_text(content) - - -def bump_tauri_conf(version: str) -> None: - path = ROOT / "tauri-app" / "src-tauri" / "tauri.conf.json" - data = json.loads(path.read_text()) - data["version"] = version - path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n") - - -def bump_package_json(version: str) -> None: - path = ROOT / "tauri-app" / "package.json" - data = json.loads(path.read_text()) - data["version"] = version - path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n") - - -def bump_package_lock_json(version: str) -> None: - path = ROOT / "tauri-app" / "package-lock.json" - content = path.read_text() - # package-lock.json 顶层的 version - content = re.sub( - r'^\s+"version": "[^"]+"', - f' "version": "{version}"', - content, - count=1, - flags=re.MULTILINE, - ) - # 顶层 packages[""] 中的 version(lockfile v3) - content = re.sub( - r'("\": \{\n[^}]*"version": ")([^"]+)(")', - rf'\g<1>{version}\g<3>', - content, - count=1, - ) - path.write_text(content) - - -def bump_auth_store(version: str) -> None: - path = ROOT / "tauri-app" / "src" / "store" / "authStore.ts" - content = path.read_text() - content = re.sub( - r"appVersion: '[^']+'", - f"appVersion: '{version}'", - content, - ) - path.write_text(content) - - -def bump_pyproject_toml(version: str) -> None: - path = ROOT / "python-api" / "pyproject.toml" - content = path.read_text() - content = re.sub( - r'^version = "[^"]+"', - f'version = "{version}"', - content, - flags=re.MULTILINE, - ) - path.write_text(content) - - -def bump_uv_lock(version: str) -> None: - path = ROOT / "python-api" / "uv.lock" - content = path.read_text() - # uv.lock 中当前包的版本(name = "meijiaka-ai-api" 后的 version) - content = re.sub( - r'(name = "meijiaka-ai-api"\nversion = ")([^"]+)(")', - rf'\g<1>{version}\g<3>', - content, - ) - path.write_text(content) - - -def bump_config_py(version: str) -> None: - path = ROOT / "python-api" / "app" / "config.py" - content = path.read_text() - content = re.sub( - r'APP_VERSION: str = Field\(default="[^"]+"', - f'APP_VERSION: str = Field(default="{version}"', - content, - ) - path.write_text(content) - - -def bump_env_example(version: str) -> None: - path = ROOT / "python-api" / ".env.example" - content = path.read_text() - content = re.sub( - r'^APP_VERSION=[^\n]+', - f'APP_VERSION={version}', - content, - flags=re.MULTILINE, - ) - path.write_text(content) - - -def create_git_tag(version: str) -> None: - tag = f"v{version}" - try: - subprocess.run( - ["git", "tag", "-a", tag, "-m", f"Release {tag}"], - cwd=ROOT, - check=True, - capture_output=True, - text=True, - ) - print(f"✅ Git tag 已创建: {tag}") - except subprocess.CalledProcessError as e: - if "already exists" in e.stderr: - print(f"⚠️ Git tag {tag} 已存在,跳过") - else: - print(f"❌ 创建 Git tag 失败: {e.stderr}") - raise - - -def main(): - if len(sys.argv) > 1: - version = sys.argv[1] - write_version(version) - print(f"VERSION 已更新为: {version}") - else: - version = read_version() - print(f"读取 VERSION: {version}") - - bump_agents_md(ROOT / "AGENTS.md", version) - bump_agents_md(ROOT / "tauri-app" / "AGENTS.md", version) - bump_cargo_toml(version) - bump_cargo_lock(version) - bump_tauri_conf(version) - bump_package_json(version) - bump_package_lock_json(version) - bump_auth_store(version) - bump_pyproject_toml(version) - bump_uv_lock(version) - bump_config_py(version) - bump_env_example(version) - - print(f"\n✅ 版本号已统一更新为: {version}") - print("\n修改的文件列表:") - print(" - VERSION") - print(" - AGENTS.md") - print(" - tauri-app/AGENTS.md") - print(" - tauri-app/package.json") - print(" - tauri-app/package-lock.json") - print(" - tauri-app/src-tauri/Cargo.toml") - print(" - tauri-app/src-tauri/Cargo.lock") - print(" - tauri-app/src-tauri/tauri.conf.json") - print(" - tauri-app/src/store/authStore.ts") - print(" - python-api/pyproject.toml") - print(" - python-api/uv.lock") - print(" - python-api/app/config.py") - print(" - python-api/.env.example") - - if len(sys.argv) > 1: - # 自动提交版本更新,确保 tag 落在正确的 commit 上 - subprocess.run( - ["git", "add", "-A"], - cwd=ROOT, - check=True, - capture_output=True, - ) - subprocess.run( - ["git", "commit", "-m", f"bump version to {version}"], - cwd=ROOT, - check=True, - capture_output=True, - ) - print(f"✅ 已提交: bump version to {version}") - create_git_tag(version) - print("\n下一步:") - print(f" git push && git push origin v{version}") - print(f" # 如果使用 GitHub Actions,同时推送到 GitHub remote:") - print(f" git push github-new && git push github-new v{version}") - - -if __name__ == "__main__": - main() diff --git a/scripts/check_all_duplicate_materials.sql b/scripts/check_all_duplicate_materials.sql deleted file mode 100644 index cc5534d..0000000 --- a/scripts/check_all_duplicate_materials.sql +++ /dev/null @@ -1,36 +0,0 @@ --- 统计全部素材中的重复命名(整个素材库) --- ============================================ - --- 1. 按 title 分组,找出重复的素材 -SELECT - title, - COUNT(*) AS duplicate_count, - STRING_AGG(DISTINCT url, ', ' ORDER BY url) AS urls, - STRING_AGG(DISTINCT CAST(id AS TEXT), ', ' ORDER BY CAST(id AS TEXT)) AS ids -FROM mjk_broll_materials -WHERE status != 'deleted' -GROUP BY title -HAVING COUNT(*) > 1 -ORDER BY duplicate_count DESC, title; - --- 2. 按 url 分组,找出重复的素材 -SELECT - url, - COUNT(*) AS duplicate_count, - STRING_AGG(DISTINCT title, ', ' ORDER BY title) AS titles, - STRING_AGG(DISTINCT CAST(id AS TEXT), ', ' ORDER BY CAST(id AS TEXT)) AS ids -FROM mjk_broll_materials -WHERE status != 'deleted' -GROUP BY url -HAVING COUNT(*) > 1 -ORDER BY duplicate_count DESC, url; - --- 3. 统计概览:总素材数、唯一 title 数、唯一 url 数 -SELECT - COUNT(*) AS total_materials, - COUNT(DISTINCT title) AS unique_titles, - COUNT(DISTINCT url) AS unique_urls, - COUNT(*) - COUNT(DISTINCT title) AS title_duplicates, - COUNT(*) - COUNT(DISTINCT url) AS url_duplicates -FROM mjk_broll_materials -WHERE status != 'deleted'; diff --git a/scripts/check_prompt_category_consistency.py b/scripts/check_prompt_category_consistency.py deleted file mode 100644 index 59c345c..0000000 --- a/scripts/check_prompt_category_consistency.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python3 -""" -检查提示词素材库标题与数据库三级分类名的一致性 -""" - -import re -from pathlib import Path -from collections import defaultdict - - -def extract_db_categories(sql_path: str) -> set[str]: - """从 seed_categories.sql 提取所有三级分类 name""" - with open(sql_path, "r", encoding="utf-8") as f: - content = f.read() - - # 匹配 level=3 的 name - matches = re.findall(r"VALUES \('[^']+', '([^']+)', \d+, 3,", content) - return set(matches) - - -def extract_prompt_titles(prompts_dir: str) -> dict[str, list[str]]: - """从提示词文件提取素材库标题""" - results = {} - dir_path = Path(prompts_dir) - - for txt_file in dir_path.rglob("*.txt"): - with open(txt_file, "r", encoding="utf-8") as f: - content = f.read() - - # 查找【内置完整素材库标题】或【内置素材库标题】部分 - marker1 = "【内置完整素材库标题】" - marker2 = "【内置素材库标题】" - - start_idx = -1 - for marker in [marker1, marker2]: - idx = content.find(marker) - if idx != -1: - start_idx = idx + len(marker) - break - - if start_idx == -1: - continue - - # 提取标题列表(到下一个【标记或文件末尾) - section = content[start_idx:] - # 找下一个【标记 - next_marker = section.find("【") - if next_marker != -1: - section = section[:next_marker] - - # 逐行解析,去除空行和注释 - titles = [] - for line in section.strip().split("\n"): - line = line.strip() - if not line or line.startswith("(") or line.startswith("备注"): - continue - # 去除可能的编号前缀如 "1、" 或 "- " - line = re.sub(r"^\d+[、.]\s*", "", line) - line = re.sub(r"^[-•]\s*", "", line) - if line: - titles.append(line) - - if titles: - results[str(txt_file.relative_to(dir_path))] = titles - - return results - - -def normalize_for_compare(text: str) -> str: - """标准化用于比较(去除空格和特殊字符)""" - return re.sub(r"\s+", "", text) - - -def main(): - db_path = Path(__file__).parent.parent / "python-api" / "scripts" / "seed_categories.sql" - prompts_dir = Path(__file__).parent.parent / "python-api" / "app" / "ai" / "prompts" / "system" - - db_categories = extract_db_categories(str(db_path)) - prompt_titles = extract_prompt_titles(str(prompts_dir)) - - print(f"数据库三级分类总数: {len(db_categories)}") - print(f"包含素材库标题的提示词文件数: {len(prompt_titles)}") - print() - - # 汇总所有提示词中的标题 - all_prompt_titles = set() - for file, titles in prompt_titles.items(): - for t in titles: - all_prompt_titles.add(t) - - print(f"提示词中素材库标题总数(去重): {len(all_prompt_titles)}") - print() - - # 对比:提示词中有但数据库中没有的 - in_prompt_not_db = [] - for title in all_prompt_titles: - if title not in db_categories and normalize_for_compare(title) not in {normalize_for_compare(c) for c in db_categories}: - in_prompt_not_db.append(title) - - # 对比:数据库中有但提示词中没有的 - in_db_not_prompt = [] - prompt_normalized = {normalize_for_compare(t) for t in all_prompt_titles} - for cat in db_categories: - if cat not in all_prompt_titles and normalize_for_compare(cat) not in prompt_normalized: - in_db_not_prompt.append(cat) - - # 统计按二级分类分组 - db_by_parent = defaultdict(list) - for cat in db_categories: - # 从分类名推断父分类,如 "卧室原始结构-毛坯基础" → "毛坯基础" - parts = cat.split("-") - if len(parts) >= 2: - parent = parts[-1] - else: - parent = "其他" - db_by_parent[parent].append(cat) - - print("=" * 60) - print("【不一致统计】") - print("=" * 60) - - print(f"\n1. 提示词中有但数据库中无(可能为错误或过时标题): {len(in_prompt_not_db)} 个") - if in_prompt_not_db: - for t in sorted(in_prompt_not_db): - print(f" - {t}") - else: - print(" (无)") - - print(f"\n2. 数据库中有但提示词中无(缺少素材引用): {len(in_db_not_prompt)} 个") - if in_db_not_prompt: - # 按父分类分组 - by_parent = defaultdict(list) - for cat in in_db_not_prompt: - parts = cat.split("-") - parent = parts[-1] if len(parts) >= 2 else "其他" - by_parent[parent].append(cat) - - for parent in sorted(by_parent.keys()): - cats = by_parent[parent] - print(f"\n 【{parent}】({len(cats)}个)") - for cat in sorted(cats): - print(f" - {cat}") - else: - print(" (无)") - - # 统计各提示词文件中的标题数量 - print(f"\n3. 各提示词文件素材库标题数量:") - for file in sorted(prompt_titles.keys()): - titles = prompt_titles[file] - # 计算该文件中与数据库不一致的数量 - mismatched = [t for t in titles if t not in db_categories and normalize_for_compare(t) not in {normalize_for_compare(c) for c in db_categories}] - status = f" ⚠️ 有{mismatched}个不一致" if mismatched else " ✅ 一致" - print(f" {file}: {len(titles)}个标题{status}") - if mismatched: - for m in mismatched: - print(f" ❌ {m}") - - # 总体匹配率 - matched = len(all_prompt_titles) - len(in_prompt_not_db) - match_rate = (matched / len(all_prompt_titles) * 100) if all_prompt_titles else 0 - print(f"\n总体匹配率: {match_rate:.1f}% ({matched}/{len(all_prompt_titles)})") - - -if __name__ == "__main__": - main() diff --git a/scripts/collect_viral_opening.py b/scripts/collect_viral_opening.py deleted file mode 100644 index 9313f60..0000000 --- a/scripts/collect_viral_opening.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -""" -网红开篇素材归集脚本 -==================== - -把所有重命名后的 .mp4 复制到一个统一目录,方便批量上传。 - -用法: - python3 scripts/collect_viral_opening.py - -输出: - /Users/0fun/Desktop/网红开篇_upload/ ← 41 个 mp4 平铺在此 -""" - -import shutil -from pathlib import Path - - -def main(): - src_dir = Path("/Users/0fun/Desktop/网红开篇") - out_dir = Path("/Users/0fun/Desktop/网红开篇_upload") - out_dir.mkdir(exist_ok=True) - - copied = 0 - for mp4_file in sorted(src_dir.rglob("*.mp4")): - if mp4_file.name.startswith("."): - continue - - dest = out_dir / mp4_file.name - shutil.copy2(mp4_file, dest) - copied += 1 - print(f"✓ {mp4_file.name}") - - print(f"\n✅ 共复制 {copied} 个文件到: {out_dir}") - - -if __name__ == "__main__": - main() diff --git a/scripts/fix_bikeng_slugs.sql b/scripts/fix_bikeng_slugs.sql deleted file mode 100644 index eeb9860..0000000 --- a/scripts/fix_bikeng_slugs.sql +++ /dev/null @@ -1,92 +0,0 @@ --- 修正 slug:去掉中文字符,改为序号格式 -BEGIN; - -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-001' WHERE name = '不要一体式卫生间' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-002' WHERE name = '不要双包套' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-003' WHERE name = '不要双开门冰箱' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-004' WHERE name = '不要反弹器' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-005' WHERE name = '不要回型吊顶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-006' WHERE name = '不要复杂吊灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-007' WHERE name = '不要复杂背景墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-008' WHERE name = '不要小双槽' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-009' WHERE name = '不要开放式收纳柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-010' WHERE name = '不要悬浮电视柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-011' WHERE name = '不要悬空马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-012' WHERE name = '不要拼色窗帘' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-013' WHERE name = '不要推拉门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-014' WHERE name = '不要插座外露' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-015' WHERE name = '不要无主灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-016' WHERE name = '不要普通门锁' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-017' WHERE name = '不要榻榻米' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-018' WHERE name = '不要正五孔插座' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-019' WHERE name = '不要洗烘一体' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-020' WHERE name = '不要深色地砖' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-021' WHERE name = '不要猫眼' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-022' WHERE name = '不要瓷砖上墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-023' WHERE name = '不要直吸马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-024' WHERE name = '不要直排下水' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-025' WHERE name = '不要筒灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-026' WHERE name = '不要罗马杠' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-027' WHERE name = '不要贵妃椅沙发' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-028' WHERE name = '不要路由器' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-029' WHERE name = '不要过门石' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-030' WHERE name = '不要造型柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-031' WHERE name = '不要阳角条' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-032' WHERE name = '不要隐形衣架' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-033' WHERE name = '不要集成灶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-034' WHERE name = '不要高光衣柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-035' WHERE name = '要一体门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-036' WHERE name = '要乳胶漆' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-037' WHERE name = '要免拉手' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-038' WHERE name = '要全屋WiFi' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-039' WHERE name = '要全屋通铺' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-040' WHERE name = '要分体灶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-041' WHERE name = '要十字开门冰箱' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-042' WHERE name = '要单包套' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-043' WHERE name = '要双眼皮' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-044' WHERE name = '要双眼皮吊顶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-045' WHERE name = '要吸顶灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-046' WHERE name = '要墙排下水' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-047' WHERE name = '要大单槽' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-048' WHERE name = '要封闭式收纳柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-049' WHERE name = '要射灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-050' WHERE name = '要干湿分离卫生间' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-051' WHERE name = '要平板柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-052' WHERE name = '要打通阳台' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-053' WHERE name = '要斜五孔插座' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-054' WHERE name = '要普通床' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-055' WHERE name = '要普通衣架' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-056' WHERE name = '要智能门锁' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-057' WHERE name = '要洗烘套装' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-058' WHERE name = '要浅色地砖' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-059' WHERE name = '要海棠角' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-060' WHERE name = '要直排沙发' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-061' WHERE name = '要窗帘盒' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-062' WHERE name = '要简约背景墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-063' WHERE name = '要纯色窗帘' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-064' WHERE name = '要肤感衣柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-065' WHERE name = '要落地电视柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-066' WHERE name = '要落地马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-067' WHERE name = '要虹吸马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-068' WHERE name = '要隐藏式插座' AND level = 3; - -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-001' WHERE name = '乳胶漆不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-002' WHERE name = '全屋角阀要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-003' WHERE name = '前置过滤器不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-004' WHERE name = '床不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-005' WHERE name = '床垫要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-006' WHERE name = '开关插座要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-007' WHERE name = '投影仪要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-008' WHERE name = '木地板要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-009' WHERE name = '木门不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-010' WHERE name = '水槽不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-011' WHERE name = '水龙头要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-012' WHERE name = '滑轨要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-013' WHERE name = '灯具不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-014' WHERE name = '瓷砖不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-015' WHERE name = '电视机不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-016' WHERE name = '窗帘不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-017' WHERE name = '腻子粉要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-018' WHERE name = '门锁要买贵的' AND level = 3; - -COMMIT; \ No newline at end of file diff --git a/scripts/fix_bikeng_slugs_pinyin.sql b/scripts/fix_bikeng_slugs_pinyin.sql deleted file mode 100644 index ea7735d..0000000 --- a/scripts/fix_bikeng_slugs_pinyin.sql +++ /dev/null @@ -1,92 +0,0 @@ --- 修正 slug:拼音首字母格式 -BEGIN; - -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byytswsj' WHERE name = '不要一体式卫生间' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bysbt' WHERE name = '不要双包套' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byskmbx' WHERE name = '不要双开门冰箱' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byftq' WHERE name = '不要反弹器' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byhxdd' WHERE name = '不要回型吊顶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byfzdd' WHERE name = '不要复杂吊灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byfzbjq' WHERE name = '不要复杂背景墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byxsc' WHERE name = '不要小双槽' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bykfssng' WHERE name = '不要开放式收纳柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byxfdsg' WHERE name = '不要悬浮电视柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byxkmt' WHERE name = '不要悬空马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bypscl' WHERE name = '不要拼色窗帘' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bytlm' WHERE name = '不要推拉门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byczwl' WHERE name = '不要插座外露' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bywzd' WHERE name = '不要无主灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byptms' WHERE name = '不要普通门锁' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byttm' WHERE name = '不要榻榻米' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byzwkcz' WHERE name = '不要正五孔插座' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byxhyt' WHERE name = '不要洗烘一体' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byssdz' WHERE name = '不要深色地砖' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bymy' WHERE name = '不要猫眼' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byczsq' WHERE name = '不要瓷砖上墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byzxmt' WHERE name = '不要直吸马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byzpxs' WHERE name = '不要直排下水' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bytd' WHERE name = '不要筒灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bylmg' WHERE name = '不要罗马杠' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bygfysf' WHERE name = '不要贵妃椅沙发' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bylyq' WHERE name = '不要路由器' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-bygms' WHERE name = '不要过门石' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byzxgm' WHERE name = '不要造型柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byyjt' WHERE name = '不要阳角条' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byyxyj' WHERE name = '不要隐形衣架' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byjcz' WHERE name = '不要集成灶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-byggygm' WHERE name = '不要高光衣柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yytm' WHERE name = '要一体门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yrjq' WHERE name = '要乳胶漆' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ymls' WHERE name = '要免拉手' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yqwwifi' WHERE name = '要全屋WiFi' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yqwtp' WHERE name = '要全屋通铺' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yftz' WHERE name = '要分体灶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yszkmbx' WHERE name = '要十字开门冰箱' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ydbt' WHERE name = '要单包套' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ysyp' WHERE name = '要双眼皮' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ysypdd' WHERE name = '要双眼皮吊顶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yxdd' WHERE name = '要吸顶灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yqpxs' WHERE name = '要墙排下水' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yddc' WHERE name = '要大单槽' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yfbssng' WHERE name = '要封闭式收纳柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ysd' WHERE name = '要射灯' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ygsflwsj' WHERE name = '要干湿分离卫生间' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ypbgm' WHERE name = '要平板柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ydtyt' WHERE name = '要打通阳台' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yxwkcz' WHERE name = '要斜五孔插座' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yptc' WHERE name = '要普通床' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yptyj' WHERE name = '要普通衣架' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yznms' WHERE name = '要智能门锁' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yxhtz' WHERE name = '要洗烘套装' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yqsdz' WHERE name = '要浅色地砖' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yhtj' WHERE name = '要海棠角' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yzpsf' WHERE name = '要直排沙发' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yclh' WHERE name = '要窗帘盒' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yjybjq' WHERE name = '要简约背景墙' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ycscl' WHERE name = '要纯色窗帘' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yfgygm' WHERE name = '要肤感衣柜门' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-ylddsg' WHERE name = '要落地电视柜' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yldmt' WHERE name = '要落地马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yhxmt' WHERE name = '要虹吸马桶' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-buyao-yycscz' WHERE name = '要隐藏式插座' AND level = 3; - -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-rjqbymgd' WHERE name = '乳胶漆不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-qwjfymgd' WHERE name = '全屋角阀要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-qzglqbymgd' WHERE name = '前置过滤器不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-cbymgd' WHERE name = '床不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-cdymgd' WHERE name = '床垫要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-kgczymgd' WHERE name = '开关插座要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-tyyymgd' WHERE name = '投影仪要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-mdbymgd' WHERE name = '木地板要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-mmbymgd' WHERE name = '木门不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-scbymgd' WHERE name = '水槽不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-sltymgd' WHERE name = '水龙头要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-hgymgd' WHERE name = '滑轨要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-djbymgd' WHERE name = '灯具不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-czbymgd' WHERE name = '瓷砖不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-dsjbymgd' WHERE name = '电视机不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-clbymgd' WHERE name = '窗帘不要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-nzfymgd' WHERE name = '腻子粉要买贵的' AND level = 3; -UPDATE mjk_broll_categories SET slug = 'bikeng-maidui-msymgd' WHERE name = '门锁要买贵的' AND level = 3; - -COMMIT; \ No newline at end of file diff --git a/scripts/fix_cover_background_url.sql b/scripts/fix_cover_background_url.sql deleted file mode 100644 index f167ea1..0000000 --- a/scripts/fix_cover_background_url.sql +++ /dev/null @@ -1,15 +0,0 @@ --- 修复封面背景图 URL:补充 script_code 子目录 --- ================================================ --- 问题:数据库中 url 字段存的路径缺少按 script_code 分组的子目录 --- 例如:meijiaka-zy/cover_templete/xxx.jpg --- 应为:meijiaka-zy/cover_templete/bk/xxx.jpg(script_code='bk' 时) --- --- 执行前建议先备份或预览受影响记录: --- SELECT id, script_code, url FROM mjk_cover_backgrounds --- WHERE url LIKE '%/cover_templete/%' --- AND url NOT LIKE '%/cover_templete/' || script_code || '/%'; - -UPDATE mjk_cover_backgrounds -SET url = REPLACE(url, '/cover_templete/', '/cover_templete/' || script_code || '/') -WHERE url LIKE '%/cover_templete/%' - AND url NOT LIKE '%/cover_templete/' || script_code || '/%'; diff --git a/scripts/generate-rounded-icon.py b/scripts/generate-rounded-icon.py deleted file mode 100644 index 909a32f..0000000 --- a/scripts/generate-rounded-icon.py +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env python3 -"""生成圆角图标:原图(透明背景 logo)作为整体,缩放居中,圆角外透明""" - -import os -from PIL import Image, ImageDraw - -ICONS_DIR = "/Users/0fun/work/meijiaka-zy/tauri-app/src-tauri/icons" -SOURCE_PNG = "/Users/0fun/work/meijiaka-zy/tauri-app/public/assets/logo.png" - -# macOS Big Sur 圆角比例 ≈ 22.6% -CORNER_RATIO_MACOS = 0.226 - -# Windows 11 风格圆角比例 ≈ 18%(Fluent Design 圆角矩形) -CORNER_RATIO_WINDOWS = 0.18 - -# 内容占画布比例(参考腾讯视频 ≈ 80.5%) -CONTENT_RATIO = 0.805 - -PNG_SIZES = [ - ("icon.png", 512), - ("128x128@2x.png", 256), - ("128x128.png", 128), - ("32x32.png", 32), - ("64x64.png", 64), -] - -SQUARE_SIZES = [ - ("Square310x310Logo.png", 310), - ("Square284x284Logo.png", 284), - ("Square150x150Logo.png", 150), - ("Square142x142Logo.png", 142), - ("Square107x107Logo.png", 107), - ("Square89x89Logo.png", 89), - ("Square71x71Logo.png", 71), - ("Square44x44Logo.png", 44), - ("Square30x30Logo.png", 30), - ("StoreLogo.png", 50), -] - - -def create_rounded_rect_mask(size: int, radius: int) -> Image.Image: - """创建圆角矩形蒙版(硬边缘)""" - mask = Image.new("L", (size, size), 0) - draw = ImageDraw.Draw(mask) - draw.rounded_rectangle((0, 0, size, size), radius=radius, fill=255) - return mask - - -def prepare_source(source: Image.Image, canvas_size: int = 1024) -> Image.Image: - """将源图居中放置在正方形透明画布上,作为后续处理的统一源图""" - src_w, src_h = source.size - canvas = Image.new("RGBA", (canvas_size, canvas_size), (0, 0, 0, 0)) - - # 等比缩放,长边充满画布的 CONTENT_RATIO - target_size = int(canvas_size * CONTENT_RATIO) - ratio = max(target_size / src_w, target_size / src_h) - new_w = int(src_w * ratio) - new_h = int(src_h * ratio) - resized = source.resize((new_w, new_h), Image.LANCZOS) - - # 居中放置 - left = (canvas_size - new_w) // 2 - top = (canvas_size - new_h) // 2 - canvas.paste(resized, (left, top), resized) - return canvas - - -def compose_icon(size: int, source: Image.Image, rounded: bool = True) -> Image.Image: - """macOS / Linux 图标:内容占画布 80.5%,大圆角""" - canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - - plate_size = int(size * CONTENT_RATIO) - plate_offset = (size - plate_size) // 2 - - # 源图等比缩放,短边充满 plate_size - src_w, src_h = source.size - ratio = max(plate_size / src_w, plate_size / src_h) - new_w = int(src_w * ratio) - new_h = int(src_h * ratio) - resized = source.resize((new_w, new_h), Image.LANCZOS) - - # 居中裁剪到 plate_size - left = (new_w - plate_size) // 2 - top = (new_h - plate_size) // 2 - img = resized.crop((left, top, left + plate_size, top + plate_size)) - - if rounded: - # 圆角蒙版裁剪(macOS / Linux) - radius = int(plate_size * CORNER_RATIO_MACOS) - mask = create_rounded_rect_mask(plate_size, radius) - canvas.paste(img, (plate_offset, plate_offset), mask) - else: - # 正方形填满 - canvas.paste(img, (plate_offset, plate_offset)) - return canvas - - -def compose_icon_windows(size: int, source: Image.Image, rounded: bool = True) -> Image.Image: - """Windows 图标:原图填满整个画布 100%,支持轻微圆角""" - canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0)) - - # 源图等比缩放,短边充满画布 - src_w, src_h = source.size - ratio = max(size / src_w, size / src_h) - new_w = int(src_w * ratio) - new_h = int(src_h * ratio) - resized = source.resize((new_w, new_h), Image.LANCZOS) - - # 居中裁剪到画布尺寸 - left = (new_w - size) // 2 - top = (new_h - size) // 2 - img = resized.crop((left, top, left + size, top + size)) - - if rounded: - # Windows 11 风格轻微圆角 - radius = max(1, int(size * CORNER_RATIO_WINDOWS)) - mask = create_rounded_rect_mask(size, radius) - canvas.paste(img, (0, 0), mask) - else: - canvas.paste(img, (0, 0)) - - return canvas - - -def generate_icns(source: Image.Image, output_path: str): - """生成 macOS .icns 文件""" - import tempfile - import subprocess - import shutil - - sizes = [16, 32, 64, 128, 256, 512, 1024] - iconset_dir = tempfile.mkdtemp(suffix=".iconset") - - for sz in sizes: - img = compose_icon(sz, source, rounded=True) - img.save(os.path.join(iconset_dir, f"icon_{sz}x{sz}.png")) - if sz <= 512: - img2x = compose_icon(sz * 2, source, rounded=True) - img2x.save(os.path.join(iconset_dir, f"icon_{sz}x{sz}@2x.png")) - - subprocess.run( - ["iconutil", "-c", "icns", iconset_dir, "-o", output_path], - check=True, - ) - shutil.rmtree(iconset_dir) - - -def generate_ico(source: Image.Image, output_path: str): - """生成 Windows .ico 文件,包含更多尺寸以支持高 DPI""" - import struct - import io - - # 添加 20x20 和 40x40 以支持 Windows 高 DPI (125%, 150%) - sizes = [16, 20, 24, 32, 40, 48, 64, 128, 256] - png_datas = [] - entries = [] - - for sz in sizes: - # Windows 图标使用轻微圆角 - img = compose_icon_windows(sz, source, rounded=True) - buf = io.BytesIO() - img.save(buf, format="PNG") - data = buf.getvalue() - png_datas.append(data) - entries.append((sz, len(data))) - - ico = struct.pack(" float | None: - """用 ffmpeg -i 提取视频时长(秒),保留 2 位小数""" - try: - result = subprocess.run( - ["ffmpeg", "-i", filepath], - capture_output=True, - text=True, - timeout=30, - ) - # ffmpeg 把信息输出到 stderr,解析 Duration: 00:00:04.25 - import re - match = re.search(r"Duration:\s+(\d+):(\d+):(\d+\.\d+)", result.stderr) - if match: - hours, minutes, seconds = match.groups() - total = float(hours) * 3600 + float(minutes) * 60 + float(seconds) - return round(total, 2) - except Exception as e: - print(f" ⚠️ 读取时长失败: {e}") - return None - - -def md5_filename(parent_name: str, original_name: str) -> str: - """ - 生成新文件名:md5(父目录名_原文件名).mp4 - - 示例: - 父目录名: 暴力拆除-恶搞开篇 - 原文件名: 5月16日(13).mp4 - 拼接: 暴力拆除-恶搞开篇_5月16日(13).mp4 - md5: a3f7b2c8... (32位十六进制) - 结果: a3f7b2c8....mp4 - """ - raw = f"{parent_name}_{original_name}" - md5_hex = hashlib.md5(raw.encode("utf-8")).hexdigest() - return f"{md5_hex}.mp4" - - -def scan_videos(src_dir: str) -> list[dict]: - """扫描目录,返回视频信息列表""" - videos = [] - src_path = Path(src_dir) - - for mp4_file in sorted(src_path.rglob("*.mp4")): - # 跳过 macOS 系统文件 - if mp4_file.name.startswith("."): - continue - - parent_folder = mp4_file.parent.name - original_name = mp4_file.name - - # 检查分类映射 - slug = FOLDER_TO_SLUG.get(parent_folder) - if not slug: - print(f"⚠️ 未找到分类映射: {parent_folder}/{original_name},跳过") - continue - - new_filename = md5_filename(parent_folder, original_name) - - print(f"📹 处理: {parent_folder}/{original_name} → {new_filename}") - duration = get_video_duration(str(mp4_file)) - if duration is None: - print(f" ❌ 无法读取时长,跳过") - continue - - videos.append({ - "original_path": str(mp4_file), - "parent_folder": parent_folder, - "original_name": original_name, - "new_filename": new_filename, - "slug": slug, - "duration": duration, - }) - - return videos - - -def generate_outputs(videos: list[dict], bucket: str, prefix: str, domain: str) -> None: - """生成上传脚本和入库 SQL""" - script_dir = Path(__file__).parent - - # 1. 生成上传脚本 - upload_script = script_dir / "viral_opening_upload.sh" - with open(upload_script, "w", encoding="utf-8") as f: - f.write("#!/bin/bash\n# 网红开篇素材批量上传脚本\n\n") - for v in videos: - cdn_url = f"{domain}/{bucket}/{prefix}/{v['new_filename']}" - f.write( - f"# {v['parent_folder']}/{v['original_name']} ({v['duration']}s)\n" - f"# qshell put {bucket} {prefix}/{v['new_filename']} " - f"'{v['original_path']}'\n" - f"# 或: qshell fput {bucket} {prefix}/{v['new_filename']} " - f"'{v['original_path']}'\n\n" - ) - os.chmod(upload_script, 0o755) - - # 2. 生成入库 SQL - sql_file = script_dir / "viral_opening_insert.sql" - with open(sql_file, "w", encoding="utf-8") as f: - f.write("-- 网红开篇素材入库 SQL\n") - f.write("-- 共 {} 个视频\n\n".format(len(videos))) - f.write("BEGIN;\n\n") - - for v in videos: - cdn_url = f"{domain}/{bucket}/{prefix}/{v['new_filename']}" - f.write( - "INSERT INTO mjk_broll_materials " - "(category_id, title, url, duration, usage_count, status, created_at, updated_at)\n" - "SELECT id, '{}', '{}', {}, 0, 'active', NOW(), NOW()\n" - "FROM mjk_broll_categories WHERE slug = '{}' AND level = 3;\n".format( - v["new_filename"], - cdn_url, - v["duration"], - v["slug"], - ) - ) - f.write( - "-- 来源: {} | 时长: {}s | 分类: {}\n\n".format( - v["parent_folder"], - v["duration"], - v["slug"], - ) - ) - - f.write("COMMIT;\n") - - # 3. 生成映射 JSON(方便核对) - mapping_file = script_dir / "viral_opening_mapping.json" - with open(mapping_file, "w", encoding="utf-8") as f: - json.dump(videos, f, ensure_ascii=False, indent=2) - - print(f"\n✅ 生成完成:") - print(f" - 上传脚本: {upload_script}") - print(f" - 入库 SQL: {sql_file}") - print(f" - 映射 JSON: {mapping_file}") - - -def main(): - parser = argparse.ArgumentParser(description="网红开篇素材批量入库") - parser.add_argument("--src", default="/Users/0fun/Desktop/网红开篇", help="素材源目录") - parser.add_argument("--bucket", default="meijiaka-zy", help="七牛云 bucket") - parser.add_argument("--prefix", default="materials", help="七牛云路径前缀") - parser.add_argument("--domain", default="https://media.liche.cn", help="CDN 域名") - args = parser.parse_args() - - if not Path(args.src).exists(): - print(f"❌ 目录不存在: {args.src}") - sys.exit(1) - - print(f"🔍 扫描目录: {args.src}\n") - videos = scan_videos(args.src) - - if not videos: - print("❌ 未找到可处理的视频") - sys.exit(1) - - print(f"\n📊 共找到 {len(videos)} 个视频") - generate_outputs(videos, args.bucket, args.prefix, args.domain) - - -if __name__ == "__main__": - main() diff --git a/scripts/insert_bikeng_materials.sql b/scripts/insert_bikeng_materials.sql deleted file mode 100644 index 6c6343e..0000000 --- a/scripts/insert_bikeng_materials.sql +++ /dev/null @@ -1,1087 +0,0 @@ --- 装修避坑素材批量导入 SQL --- 共 1082 个素材(86个三级分类) --- URL前缀: https://media.liche.cn/meijiaka-zy/materials/ - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) VALUES - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '264033ee6c3c4e9381a605ecf9d65973', 'https://media.liche.cn/meijiaka-zy/materials/264033ee6c3c4e9381a605ecf9d65973.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '082e54eb52ce40188223d0ee42816df7', 'https://media.liche.cn/meijiaka-zy/materials/082e54eb52ce40188223d0ee42816df7.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'a1bc6520e25047cba05a3044ac960f73', 'https://media.liche.cn/meijiaka-zy/materials/a1bc6520e25047cba05a3044ac960f73.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '2ef8ed8427044ce29f2eae9d23aab7ca', 'https://media.liche.cn/meijiaka-zy/materials/2ef8ed8427044ce29f2eae9d23aab7ca.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '590ea27930c4482292f7568225190d61', 'https://media.liche.cn/meijiaka-zy/materials/590ea27930c4482292f7568225190d61.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '52941a626cff4981ae5aa742583ae90c', 'https://media.liche.cn/meijiaka-zy/materials/52941a626cff4981ae5aa742583ae90c.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '5c2c8ffec1f546f78760ef3b4f606812', 'https://media.liche.cn/meijiaka-zy/materials/5c2c8ffec1f546f78760ef3b4f606812.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'ed7c02f691f74cea9bda9bfa1ea1c841', 'https://media.liche.cn/meijiaka-zy/materials/ed7c02f691f74cea9bda9bfa1ea1c841.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '896797ea89374f2aa417cb11efb46a48', 'https://media.liche.cn/meijiaka-zy/materials/896797ea89374f2aa417cb11efb46a48.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '1fab462ab3bd4ffb97754049dbd6c465', 'https://media.liche.cn/meijiaka-zy/materials/1fab462ab3bd4ffb97754049dbd6c465.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'f73c1d2d995547b09c1d1a2ada098db4', 'https://media.liche.cn/meijiaka-zy/materials/f73c1d2d995547b09c1d1a2ada098db4.mp4', 3.17, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '2d814a48f1f04cafb419de8559fe84b1', 'https://media.liche.cn/meijiaka-zy/materials/2d814a48f1f04cafb419de8559fe84b1.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'df27530282ab4b6ea3cad27912cbc74c', 'https://media.liche.cn/meijiaka-zy/materials/df27530282ab4b6ea3cad27912cbc74c.mp4', 3.09, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '3974c797de614ba4a81ac83df81418bf', 'https://media.liche.cn/meijiaka-zy/materials/3974c797de614ba4a81ac83df81418bf.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'b3744fca79264f9db05f64235f9f8e9a', 'https://media.liche.cn/meijiaka-zy/materials/b3744fca79264f9db05f64235f9f8e9a.mp4', 3.25, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'b29b96b24e494e85b5c28c8bc9aea367', 'https://media.liche.cn/meijiaka-zy/materials/b29b96b24e494e85b5c28c8bc9aea367.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'be52d243f7a64c249f48954f13cbd2f9', 'https://media.liche.cn/meijiaka-zy/materials/be52d243f7a64c249f48954f13cbd2f9.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'ffe54aad95e54ce7862a79637b68af27', 'https://media.liche.cn/meijiaka-zy/materials/ffe54aad95e54ce7862a79637b68af27.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), 'f076ef295b49494ea99c40e92efc7a33', 'https://media.liche.cn/meijiaka-zy/materials/f076ef295b49494ea99c40e92efc7a33.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '6d7cbab16b9a43e8a6f72f10a26fcd4a', 'https://media.liche.cn/meijiaka-zy/materials/6d7cbab16b9a43e8a6f72f10a26fcd4a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '128c5379839a490e8440a57b9e9f5525', 'https://media.liche.cn/meijiaka-zy/materials/128c5379839a490e8440a57b9e9f5525.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '61b860f244c748218e78f07e741ec977', 'https://media.liche.cn/meijiaka-zy/materials/61b860f244c748218e78f07e741ec977.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '74819e6d95704659a67e83a42fbac5b5', 'https://media.liche.cn/meijiaka-zy/materials/74819e6d95704659a67e83a42fbac5b5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '06c176aa0d864b7495feb0db8df18a6b', 'https://media.liche.cn/meijiaka-zy/materials/06c176aa0d864b7495feb0db8df18a6b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉要买贵的' AND level = 3), '4791b044253b487d83760376573654e4', 'https://media.liche.cn/meijiaka-zy/materials/4791b044253b487d83760376573654e4.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '015042c5308741d09ae2b33905ee9133', 'https://media.liche.cn/meijiaka-zy/materials/015042c5308741d09ae2b33905ee9133.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '9d6ff2b8f9be4e548db61cb6873d6afe', 'https://media.liche.cn/meijiaka-zy/materials/9d6ff2b8f9be4e548db61cb6873d6afe.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'e03cd01f10bd4b16b825c6e340866dc3', 'https://media.liche.cn/meijiaka-zy/materials/e03cd01f10bd4b16b825c6e340866dc3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'e8666ed445644ebe8852f1015089fe4c', 'https://media.liche.cn/meijiaka-zy/materials/e8666ed445644ebe8852f1015089fe4c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '67dc2c998cd347f9a2dd34d3dc619e7d', 'https://media.liche.cn/meijiaka-zy/materials/67dc2c998cd347f9a2dd34d3dc619e7d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '03057a631ea442f0913994de0c218f34', 'https://media.liche.cn/meijiaka-zy/materials/03057a631ea442f0913994de0c218f34.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '88da12d70fb54507ad7284c62874c54a', 'https://media.liche.cn/meijiaka-zy/materials/88da12d70fb54507ad7284c62874c54a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '6f5cd8afc5c1469a864acf5b5adf8b70', 'https://media.liche.cn/meijiaka-zy/materials/6f5cd8afc5c1469a864acf5b5adf8b70.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '6afe43014ee945cc990f551ca362a7db', 'https://media.liche.cn/meijiaka-zy/materials/6afe43014ee945cc990f551ca362a7db.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '9d01d12c38634e3ba86cccc7b582ef06', 'https://media.liche.cn/meijiaka-zy/materials/9d01d12c38634e3ba86cccc7b582ef06.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'd5188cd070f54899b533c5aacdbaf2ac', 'https://media.liche.cn/meijiaka-zy/materials/d5188cd070f54899b533c5aacdbaf2ac.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '6a63c02002454f1c94f7a67d1d5fe88e', 'https://media.liche.cn/meijiaka-zy/materials/6a63c02002454f1c94f7a67d1d5fe88e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'ab6f349753324253ba3f1bb6fbf0a6f6', 'https://media.liche.cn/meijiaka-zy/materials/ab6f349753324253ba3f1bb6fbf0a6f6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '3eb5922dac274d828422aa8a41b86b7f', 'https://media.liche.cn/meijiaka-zy/materials/3eb5922dac274d828422aa8a41b86b7f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '19d02d78867645b298309f5611334301', 'https://media.liche.cn/meijiaka-zy/materials/19d02d78867645b298309f5611334301.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '8c223a380881416f9c74e2b2af88eb6b', 'https://media.liche.cn/meijiaka-zy/materials/8c223a380881416f9c74e2b2af88eb6b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '76499b007e6349d9be257d80fff43441', 'https://media.liche.cn/meijiaka-zy/materials/76499b007e6349d9be257d80fff43441.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'c772a574dadd4051b8e4f4c2077968d9', 'https://media.liche.cn/meijiaka-zy/materials/c772a574dadd4051b8e4f4c2077968d9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '6cdb0b13d0e34119aed094fe1ca1cfe3', 'https://media.liche.cn/meijiaka-zy/materials/6cdb0b13d0e34119aed094fe1ca1cfe3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '675d7650a95848cd9768d7268f055580', 'https://media.liche.cn/meijiaka-zy/materials/675d7650a95848cd9768d7268f055580.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), 'db98be6619694da48058188e766a8489', 'https://media.liche.cn/meijiaka-zy/materials/db98be6619694da48058188e766a8489.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床不要买贵的' AND level = 3), '14843c19adb04ae5976bac398c2d48f9', 'https://media.liche.cn/meijiaka-zy/materials/14843c19adb04ae5976bac398c2d48f9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'f01d14e731e74da89172f7826a5f2f94', 'https://media.liche.cn/meijiaka-zy/materials/f01d14e731e74da89172f7826a5f2f94.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '962dc6c5f17049d8a58dba4963848f9f', 'https://media.liche.cn/meijiaka-zy/materials/962dc6c5f17049d8a58dba4963848f9f.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '6c4ca4f439a947988474b1e99d6f71d3', 'https://media.liche.cn/meijiaka-zy/materials/6c4ca4f439a947988474b1e99d6f71d3.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '3fbf978439c84be6b042230c844f827c', 'https://media.liche.cn/meijiaka-zy/materials/3fbf978439c84be6b042230c844f827c.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '4017302925344189a8248dea03b8c148', 'https://media.liche.cn/meijiaka-zy/materials/4017302925344189a8248dea03b8c148.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'cce9c78f66934699994da41ac93da3d2', 'https://media.liche.cn/meijiaka-zy/materials/cce9c78f66934699994da41ac93da3d2.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'b23892afb7f745c782de644bcdf0c332', 'https://media.liche.cn/meijiaka-zy/materials/b23892afb7f745c782de644bcdf0c332.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '2b32432282964d2ebc16af828772b983', 'https://media.liche.cn/meijiaka-zy/materials/2b32432282964d2ebc16af828772b983.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '944916bc311b44cbbf3e5ae1499a1507', 'https://media.liche.cn/meijiaka-zy/materials/944916bc311b44cbbf3e5ae1499a1507.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'd03066e8686140978c63cbb22f068dc8', 'https://media.liche.cn/meijiaka-zy/materials/d03066e8686140978c63cbb22f068dc8.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '02c3d3eb431b45ed922d963e567d4e17', 'https://media.liche.cn/meijiaka-zy/materials/02c3d3eb431b45ed922d963e567d4e17.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '7c51724efa4b4ea1a6a070510f885ea3', 'https://media.liche.cn/meijiaka-zy/materials/7c51724efa4b4ea1a6a070510f885ea3.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '8507d0016c3643a3815fa21a1959f303', 'https://media.liche.cn/meijiaka-zy/materials/8507d0016c3643a3815fa21a1959f303.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '38d70be2384e4c1182397011912cbd02', 'https://media.liche.cn/meijiaka-zy/materials/38d70be2384e4c1182397011912cbd02.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '0b65aa1163524d9e961c79003e06e2ca', 'https://media.liche.cn/meijiaka-zy/materials/0b65aa1163524d9e961c79003e06e2ca.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '0320edd7a95044acbaf37dc96fb57c34', 'https://media.liche.cn/meijiaka-zy/materials/0320edd7a95044acbaf37dc96fb57c34.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '2bb036d823364d14934bb41ebc08e128', 'https://media.liche.cn/meijiaka-zy/materials/2bb036d823364d14934bb41ebc08e128.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '6a921de4bfe5430288bf08c604ecd345', 'https://media.liche.cn/meijiaka-zy/materials/6a921de4bfe5430288bf08c604ecd345.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '4503c5db78954d6f9a54e757b6ad4a0c', 'https://media.liche.cn/meijiaka-zy/materials/4503c5db78954d6f9a54e757b6ad4a0c.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '7d4d23ae1f5a44db9052eb13561ced02', 'https://media.liche.cn/meijiaka-zy/materials/7d4d23ae1f5a44db9052eb13561ced02.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'dc81201fbd2c41ca94587268a464deb2', 'https://media.liche.cn/meijiaka-zy/materials/dc81201fbd2c41ca94587268a464deb2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '94c2d51c7b5840b5b824b35f1688851a', 'https://media.liche.cn/meijiaka-zy/materials/94c2d51c7b5840b5b824b35f1688851a.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '4d26133656ba4438b9d29fb90804d648', 'https://media.liche.cn/meijiaka-zy/materials/4d26133656ba4438b9d29fb90804d648.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '83087ada57874832ad5a09f5b72c8c36', 'https://media.liche.cn/meijiaka-zy/materials/83087ada57874832ad5a09f5b72c8c36.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '6a59f230d4ee4224be016c7409a11c2c', 'https://media.liche.cn/meijiaka-zy/materials/6a59f230d4ee4224be016c7409a11c2c.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '88c98b2d06314cc1933ac625e0301d62', 'https://media.liche.cn/meijiaka-zy/materials/88c98b2d06314cc1933ac625e0301d62.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'cafcb6dbf579454e86d871551f51a5d2', 'https://media.liche.cn/meijiaka-zy/materials/cafcb6dbf579454e86d871551f51a5d2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '89304279ea4d4c74ac655a0b8d0b1571', 'https://media.liche.cn/meijiaka-zy/materials/89304279ea4d4c74ac655a0b8d0b1571.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'bbbd75b7d7f84724a849e294f78d5858', 'https://media.liche.cn/meijiaka-zy/materials/bbbd75b7d7f84724a849e294f78d5858.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'e68531b36c914c329031236224adf3c2', 'https://media.liche.cn/meijiaka-zy/materials/e68531b36c914c329031236224adf3c2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '1f8f413c66e440d98fbd759cb28b76fd', 'https://media.liche.cn/meijiaka-zy/materials/1f8f413c66e440d98fbd759cb28b76fd.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '63bb97134f01465a9dd3fe70e7ac78b7', 'https://media.liche.cn/meijiaka-zy/materials/63bb97134f01465a9dd3fe70e7ac78b7.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '76b07b1d5f154bb591bd4d52d8595387', 'https://media.liche.cn/meijiaka-zy/materials/76b07b1d5f154bb591bd4d52d8595387.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'f635dd904d4b4283b8d309f8f09a7dab', 'https://media.liche.cn/meijiaka-zy/materials/f635dd904d4b4283b8d309f8f09a7dab.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '82ec1888071446388d84b15b9043a91d', 'https://media.liche.cn/meijiaka-zy/materials/82ec1888071446388d84b15b9043a91d.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '7760a624a88b46e1837ac297c074d475', 'https://media.liche.cn/meijiaka-zy/materials/7760a624a88b46e1837ac297c074d475.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'da00e41d90db4602b493dc0d1bdef188', 'https://media.liche.cn/meijiaka-zy/materials/da00e41d90db4602b493dc0d1bdef188.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'df1b67b737bc4b679a416c9d6813dcf1', 'https://media.liche.cn/meijiaka-zy/materials/df1b67b737bc4b679a416c9d6813dcf1.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '482580d7bd2c46dca5f5e791bd07487a', 'https://media.liche.cn/meijiaka-zy/materials/482580d7bd2c46dca5f5e791bd07487a.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), 'c6537869bd6f4477b96d9d7903890887', 'https://media.liche.cn/meijiaka-zy/materials/c6537869bd6f4477b96d9d7903890887.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'bc4a3a8e52ac488c8badf19f1cbb9f3e', 'https://media.liche.cn/meijiaka-zy/materials/bc4a3a8e52ac488c8badf19f1cbb9f3e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'cd661a0ee8714db1a3a16b7517014859', 'https://media.liche.cn/meijiaka-zy/materials/cd661a0ee8714db1a3a16b7517014859.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'd0ed617a89f44f0aa715fcd97abaecc2', 'https://media.liche.cn/meijiaka-zy/materials/d0ed617a89f44f0aa715fcd97abaecc2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '56db0c8177b742ee9841f0fed29e3357', 'https://media.liche.cn/meijiaka-zy/materials/56db0c8177b742ee9841f0fed29e3357.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '门锁要买贵的' AND level = 3), '460156bb47a7418bbdb459c1d6210c40', 'https://media.liche.cn/meijiaka-zy/materials/460156bb47a7418bbdb459c1d6210c40.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'bb9267578ec3482a966474abb0d201f0', 'https://media.liche.cn/meijiaka-zy/materials/bb9267578ec3482a966474abb0d201f0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '0ec2e3f7c33c41f9a75a552598ed5bd6', 'https://media.liche.cn/meijiaka-zy/materials/0ec2e3f7c33c41f9a75a552598ed5bd6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'a5e3e14ca2284751b8cd2176addbeb58', 'https://media.liche.cn/meijiaka-zy/materials/a5e3e14ca2284751b8cd2176addbeb58.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '5c4f93a077db4882a894fccc3715fb66', 'https://media.liche.cn/meijiaka-zy/materials/5c4f93a077db4882a894fccc3715fb66.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '146d6d02785d4fda95ed6c3345c02794', 'https://media.liche.cn/meijiaka-zy/materials/146d6d02785d4fda95ed6c3345c02794.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '7a28ad60d16a42fb9cac5f6c8445bc12', 'https://media.liche.cn/meijiaka-zy/materials/7a28ad60d16a42fb9cac5f6c8445bc12.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '0280b066f742491ea4e5637f93bff2e9', 'https://media.liche.cn/meijiaka-zy/materials/0280b066f742491ea4e5637f93bff2e9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'd5b236b1cf7244ffa09fe4b839c03af7', 'https://media.liche.cn/meijiaka-zy/materials/d5b236b1cf7244ffa09fe4b839c03af7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'aed2f99f199f4c62a479c0e8330406ab', 'https://media.liche.cn/meijiaka-zy/materials/aed2f99f199f4c62a479c0e8330406ab.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '5bf3d9e0a8f54b64ac49d3c55334e8aa', 'https://media.liche.cn/meijiaka-zy/materials/5bf3d9e0a8f54b64ac49d3c55334e8aa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '0150c5e3af8f4ccb8ab719402cfda1e0', 'https://media.liche.cn/meijiaka-zy/materials/0150c5e3af8f4ccb8ab719402cfda1e0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '251797015ffc44ba8455d58821d5058b', 'https://media.liche.cn/meijiaka-zy/materials/251797015ffc44ba8455d58821d5058b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '46db3f8ba2a240728b661b324e3b7f48', 'https://media.liche.cn/meijiaka-zy/materials/46db3f8ba2a240728b661b324e3b7f48.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '9da5ddf92c364297acc091970b710d3f', 'https://media.liche.cn/meijiaka-zy/materials/9da5ddf92c364297acc091970b710d3f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'b0536e7bfae546848e570bf220bd70a8', 'https://media.liche.cn/meijiaka-zy/materials/b0536e7bfae546848e570bf220bd70a8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '4ba9fae9d0fa4467862ca2861a14797d', 'https://media.liche.cn/meijiaka-zy/materials/4ba9fae9d0fa4467862ca2861a14797d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'e37d8bf8ddc94611be3ac6f96ecc3f30', 'https://media.liche.cn/meijiaka-zy/materials/e37d8bf8ddc94611be3ac6f96ecc3f30.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '320aae3e093f4b3dae3de6a5e61158f7', 'https://media.liche.cn/meijiaka-zy/materials/320aae3e093f4b3dae3de6a5e61158f7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), 'b27bd38da2ae4e46987b79b7742839bb', 'https://media.liche.cn/meijiaka-zy/materials/b27bd38da2ae4e46987b79b7742839bb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '095e97e6889b4476bfdd5fe41aeb271d', 'https://media.liche.cn/meijiaka-zy/materials/095e97e6889b4476bfdd5fe41aeb271d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座要买贵的' AND level = 3), '25f3e268865a4020b2357ca6f701d2fe', 'https://media.liche.cn/meijiaka-zy/materials/25f3e268865a4020b2357ca6f701d2fe.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'a842546a728a4acbbbc7e9ede2cbd573', 'https://media.liche.cn/meijiaka-zy/materials/a842546a728a4acbbbc7e9ede2cbd573.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '50d97865515849eaa25388a1b5fd30fc', 'https://media.liche.cn/meijiaka-zy/materials/50d97865515849eaa25388a1b5fd30fc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '9c50a144cbb34feca93e8a6869031775', 'https://media.liche.cn/meijiaka-zy/materials/9c50a144cbb34feca93e8a6869031775.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '0277cc5b2a2f4a0688d0b7e9d6c7b2ad', 'https://media.liche.cn/meijiaka-zy/materials/0277cc5b2a2f4a0688d0b7e9d6c7b2ad.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'de775d5552034a5fa8e16820488e4a25', 'https://media.liche.cn/meijiaka-zy/materials/de775d5552034a5fa8e16820488e4a25.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '9cf4396b4c654fdf89bdcc7ff031d5e8', 'https://media.liche.cn/meijiaka-zy/materials/9cf4396b4c654fdf89bdcc7ff031d5e8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '2736c4094714489cb03f502bcfc2ffda', 'https://media.liche.cn/meijiaka-zy/materials/2736c4094714489cb03f502bcfc2ffda.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'bbdafb02236d43dc9a8c68e395303e28', 'https://media.liche.cn/meijiaka-zy/materials/bbdafb02236d43dc9a8c68e395303e28.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'a6eafb841dd247ecb7d661eb4f55d922', 'https://media.liche.cn/meijiaka-zy/materials/a6eafb841dd247ecb7d661eb4f55d922.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '84b352941b4a4e91a038316eb6731fa9', 'https://media.liche.cn/meijiaka-zy/materials/84b352941b4a4e91a038316eb6731fa9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '8f11ce0fe71c4f5eb91201a7f2ccb0f1', 'https://media.liche.cn/meijiaka-zy/materials/8f11ce0fe71c4f5eb91201a7f2ccb0f1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '82e1c5547a474f42a9a83dc5397ff026', 'https://media.liche.cn/meijiaka-zy/materials/82e1c5547a474f42a9a83dc5397ff026.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'e60db719d2c74df0a1272da1e589dca4', 'https://media.liche.cn/meijiaka-zy/materials/e60db719d2c74df0a1272da1e589dca4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'ebf6c4e39bc843d28829f65b493ee58f', 'https://media.liche.cn/meijiaka-zy/materials/ebf6c4e39bc843d28829f65b493ee58f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '44a7eeaef1cc4d76b8f6197605c13160', 'https://media.liche.cn/meijiaka-zy/materials/44a7eeaef1cc4d76b8f6197605c13160.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'b128441f56054c7d84f47c4b6cea3ea5', 'https://media.liche.cn/meijiaka-zy/materials/b128441f56054c7d84f47c4b6cea3ea5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'ea1521179c29485f8c930c03d71fe3fa', 'https://media.liche.cn/meijiaka-zy/materials/ea1521179c29485f8c930c03d71fe3fa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'd48427a39c00424281612c6cc94732fe', 'https://media.liche.cn/meijiaka-zy/materials/d48427a39c00424281612c6cc94732fe.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'f27a2b7bddf44b9bb66d3ea13bec0588', 'https://media.liche.cn/meijiaka-zy/materials/f27a2b7bddf44b9bb66d3ea13bec0588.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '84ca1b1f6acd4f9cafaae5899b908605', 'https://media.liche.cn/meijiaka-zy/materials/84ca1b1f6acd4f9cafaae5899b908605.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '60102ea593b44dfd9027892b378de007', 'https://media.liche.cn/meijiaka-zy/materials/60102ea593b44dfd9027892b378de007.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '2ec518b9d01646ec8cb2363d046c1393', 'https://media.liche.cn/meijiaka-zy/materials/2ec518b9d01646ec8cb2363d046c1393.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '184e3918baae433292fd6c614fbddb51', 'https://media.liche.cn/meijiaka-zy/materials/184e3918baae433292fd6c614fbddb51.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'c67f5b4ac38e4ebeb6e9164fc4e5458f', 'https://media.liche.cn/meijiaka-zy/materials/c67f5b4ac38e4ebeb6e9164fc4e5458f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'cc6b9343c31c489596fbe8a0dd842a4f', 'https://media.liche.cn/meijiaka-zy/materials/cc6b9343c31c489596fbe8a0dd842a4f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'a74feb655a4c407d8cca06a4d6a97030', 'https://media.liche.cn/meijiaka-zy/materials/a74feb655a4c407d8cca06a4d6a97030.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '3582c0a7209146febfc0d025b0328081', 'https://media.liche.cn/meijiaka-zy/materials/3582c0a7209146febfc0d025b0328081.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), 'b346e9261979435da402cf7b0b62948b', 'https://media.liche.cn/meijiaka-zy/materials/b346e9261979435da402cf7b0b62948b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '2dd1b72d98484dbbadac664e8515f498', 'https://media.liche.cn/meijiaka-zy/materials/2dd1b72d98484dbbadac664e8515f498.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '5b2a87f722884811953f2cbac45f1b8b', 'https://media.liche.cn/meijiaka-zy/materials/5b2a87f722884811953f2cbac45f1b8b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '1ae1797b2ed84f239fe42f23b27e0d3f', 'https://media.liche.cn/meijiaka-zy/materials/1ae1797b2ed84f239fe42f23b27e0d3f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '85ce61b7c65846a897bad5c49c63a00b', 'https://media.liche.cn/meijiaka-zy/materials/85ce61b7c65846a897bad5c49c63a00b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'd2fee0125b054ef3b538b374165ed0e8', 'https://media.liche.cn/meijiaka-zy/materials/d2fee0125b054ef3b538b374165ed0e8.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '70fc78bdb1cb44769647e82064a72174', 'https://media.liche.cn/meijiaka-zy/materials/70fc78bdb1cb44769647e82064a72174.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视机不要买贵的' AND level = 3), '8539e542d0204ac89362307f13d246e2', 'https://media.liche.cn/meijiaka-zy/materials/8539e542d0204ac89362307f13d246e2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'f1b553d8d27d4399a0c1417f1361d017', 'https://media.liche.cn/meijiaka-zy/materials/f1b553d8d27d4399a0c1417f1361d017.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'e7da8708b2f74afaabc0c3e1d0ae81ce', 'https://media.liche.cn/meijiaka-zy/materials/e7da8708b2f74afaabc0c3e1d0ae81ce.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '00110ed81f0046658d0127edaefcf2eb', 'https://media.liche.cn/meijiaka-zy/materials/00110ed81f0046658d0127edaefcf2eb.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'a83a05da0f824c0989bef70cb74c4756', 'https://media.liche.cn/meijiaka-zy/materials/a83a05da0f824c0989bef70cb74c4756.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '17a14c4b666c4bde83cda07d35d4d922', 'https://media.liche.cn/meijiaka-zy/materials/17a14c4b666c4bde83cda07d35d4d922.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'b118a25b7d4d44c2982f99763b04c8e8', 'https://media.liche.cn/meijiaka-zy/materials/b118a25b7d4d44c2982f99763b04c8e8.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '6d88e35c300b488389639c52aac53e04', 'https://media.liche.cn/meijiaka-zy/materials/6d88e35c300b488389639c52aac53e04.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '0cc15b6578604e418c6c81993c20ec4a', 'https://media.liche.cn/meijiaka-zy/materials/0cc15b6578604e418c6c81993c20ec4a.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'dad0fb5afb0c481fac260db2ab74b709', 'https://media.liche.cn/meijiaka-zy/materials/dad0fb5afb0c481fac260db2ab74b709.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'b70b53e776724fbcbb60828621bc0fc7', 'https://media.liche.cn/meijiaka-zy/materials/b70b53e776724fbcbb60828621bc0fc7.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'b0e36b77d3aa40bfa2acc4173d678a12', 'https://media.liche.cn/meijiaka-zy/materials/b0e36b77d3aa40bfa2acc4173d678a12.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '29c1e5fbfcd14b25b405ba1ff054997b', 'https://media.liche.cn/meijiaka-zy/materials/29c1e5fbfcd14b25b405ba1ff054997b.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '2c78c300327f4a74ae927ad5fb71b68f', 'https://media.liche.cn/meijiaka-zy/materials/2c78c300327f4a74ae927ad5fb71b68f.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '3b0a585416c84ff196744f410a92d74d', 'https://media.liche.cn/meijiaka-zy/materials/3b0a585416c84ff196744f410a92d74d.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'c44e8961ce994fceb14ea834013243eb', 'https://media.liche.cn/meijiaka-zy/materials/c44e8961ce994fceb14ea834013243eb.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '526e7d7f4cb04a8a97f3b2c764930e8a', 'https://media.liche.cn/meijiaka-zy/materials/526e7d7f4cb04a8a97f3b2c764930e8a.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'f683eb3256b0456bb8d78462723dfead', 'https://media.liche.cn/meijiaka-zy/materials/f683eb3256b0456bb8d78462723dfead.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'b0e14cdbea784aa699f32125059571c8', 'https://media.liche.cn/meijiaka-zy/materials/b0e14cdbea784aa699f32125059571c8.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '47d1fcf9b02d47ebbe858bc54ea253f4', 'https://media.liche.cn/meijiaka-zy/materials/47d1fcf9b02d47ebbe858bc54ea253f4.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '435174b1912a48db9b55c034d108bf07', 'https://media.liche.cn/meijiaka-zy/materials/435174b1912a48db9b55c034d108bf07.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '7268e69a1f4f45b5ba0bc0233433bf66', 'https://media.liche.cn/meijiaka-zy/materials/7268e69a1f4f45b5ba0bc0233433bf66.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '37b710125a1047a1a5eb730197ce2397', 'https://media.liche.cn/meijiaka-zy/materials/37b710125a1047a1a5eb730197ce2397.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '542e7172faaf4d1d97ac7fb120b0eaf5', 'https://media.liche.cn/meijiaka-zy/materials/542e7172faaf4d1d97ac7fb120b0eaf5.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '97530c5f244e4a008f5fee2d5c309c26', 'https://media.liche.cn/meijiaka-zy/materials/97530c5f244e4a008f5fee2d5c309c26.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'e95dcca3b09b4b638d7f042dc63495e7', 'https://media.liche.cn/meijiaka-zy/materials/e95dcca3b09b4b638d7f042dc63495e7.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'bda3f61634454eb9bd3bd59aa3f988f7', 'https://media.liche.cn/meijiaka-zy/materials/bda3f61634454eb9bd3bd59aa3f988f7.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '9cd12649b28748ef89c39d9edabebf16', 'https://media.liche.cn/meijiaka-zy/materials/9cd12649b28748ef89c39d9edabebf16.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), 'f36cf8cfce7047d7928882ed6ce77e98', 'https://media.liche.cn/meijiaka-zy/materials/f36cf8cfce7047d7928882ed6ce77e98.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '77cb0e4d45c24cec886e6fba07219c22', 'https://media.liche.cn/meijiaka-zy/materials/77cb0e4d45c24cec886e6fba07219c22.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'c41f2eb412a44b4e842079a7f9685815', 'https://media.liche.cn/meijiaka-zy/materials/c41f2eb412a44b4e842079a7f9685815.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'fcb65de4a74b4535833126a0f3b26728', 'https://media.liche.cn/meijiaka-zy/materials/fcb65de4a74b4535833126a0f3b26728.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'b50239e57ce845e8abd121376cac68cc', 'https://media.liche.cn/meijiaka-zy/materials/b50239e57ce845e8abd121376cac68cc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '7156b592210e416d80337ea94709d52b', 'https://media.liche.cn/meijiaka-zy/materials/7156b592210e416d80337ea94709d52b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '7591b48007264df68c5b4144a5ae76d7', 'https://media.liche.cn/meijiaka-zy/materials/7591b48007264df68c5b4144a5ae76d7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'eba8efb18011462c80144fd7bfd6d635', 'https://media.liche.cn/meijiaka-zy/materials/eba8efb18011462c80144fd7bfd6d635.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水龙头要买贵的' AND level = 3), '31427a77580e428dae870d09094b9e27', 'https://media.liche.cn/meijiaka-zy/materials/31427a77580e428dae870d09094b9e27.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '2e18fa79567f48eaac3d0413d1314e03', 'https://media.liche.cn/meijiaka-zy/materials/2e18fa79567f48eaac3d0413d1314e03.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'c91b7a803869419193753df5c2811330', 'https://media.liche.cn/meijiaka-zy/materials/c91b7a803869419193753df5c2811330.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'fa7054cb4af740b3a4b3e96d61896094', 'https://media.liche.cn/meijiaka-zy/materials/fa7054cb4af740b3a4b3e96d61896094.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'bb62d35890864a97841d39f17ae6af9a', 'https://media.liche.cn/meijiaka-zy/materials/bb62d35890864a97841d39f17ae6af9a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), 'f2cb43a744b54fd08c6a0429ae832fd4', 'https://media.liche.cn/meijiaka-zy/materials/f2cb43a744b54fd08c6a0429ae832fd4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '446c4ec9e3384cafa2b42aee88ecc42d', 'https://media.liche.cn/meijiaka-zy/materials/446c4ec9e3384cafa2b42aee88ecc42d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'a3f2ff40cf534a14a6fa557c29e275d8', 'https://media.liche.cn/meijiaka-zy/materials/a3f2ff40cf534a14a6fa557c29e275d8.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '前置过滤器不要买贵的' AND level = 3), '76288ae0c19b422d896ed90972052fb5', 'https://media.liche.cn/meijiaka-zy/materials/76288ae0c19b422d896ed90972052fb5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'c53460bfa96e41c0b000b4c57b2f7193', 'https://media.liche.cn/meijiaka-zy/materials/c53460bfa96e41c0b000b4c57b2f7193.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '30801aaafae047b7a9d55a5e358eb264', 'https://media.liche.cn/meijiaka-zy/materials/30801aaafae047b7a9d55a5e358eb264.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'd0629a36dcd5456c90007b0ff0bf2e01', 'https://media.liche.cn/meijiaka-zy/materials/d0629a36dcd5456c90007b0ff0bf2e01.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '95aa07a273ab44db8cff179de7dd80d6', 'https://media.liche.cn/meijiaka-zy/materials/95aa07a273ab44db8cff179de7dd80d6.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '2c80a10a13cd408cbadbb6fb11b8c5d0', 'https://media.liche.cn/meijiaka-zy/materials/2c80a10a13cd408cbadbb6fb11b8c5d0.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '405eb45a230540af92948c1b26d0804c', 'https://media.liche.cn/meijiaka-zy/materials/405eb45a230540af92948c1b26d0804c.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'cb7377012d1a4bb4ba509d0386f95bb6', 'https://media.liche.cn/meijiaka-zy/materials/cb7377012d1a4bb4ba509d0386f95bb6.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'bcf74f12104f4b9898eddb4d34b2a72b', 'https://media.liche.cn/meijiaka-zy/materials/bcf74f12104f4b9898eddb4d34b2a72b.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'a86561e63e4a4f36881632c1c96c892c', 'https://media.liche.cn/meijiaka-zy/materials/a86561e63e4a4f36881632c1c96c892c.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '8c6a1676ca4843afb9a3f8cd458c7979', 'https://media.liche.cn/meijiaka-zy/materials/8c6a1676ca4843afb9a3f8cd458c7979.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '40c86bbd0fa142ab9f6755680030327e', 'https://media.liche.cn/meijiaka-zy/materials/40c86bbd0fa142ab9f6755680030327e.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '5c8d76fef37b4b6882eeeceafa199746', 'https://media.liche.cn/meijiaka-zy/materials/5c8d76fef37b4b6882eeeceafa199746.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '06aec8bebc974b89a7daf1de70423870', 'https://media.liche.cn/meijiaka-zy/materials/06aec8bebc974b89a7daf1de70423870.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '993cbe5b1d9440c7bd25fea897d36fde', 'https://media.liche.cn/meijiaka-zy/materials/993cbe5b1d9440c7bd25fea897d36fde.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'd95adf6eef414a7396edf2c9accba39e', 'https://media.liche.cn/meijiaka-zy/materials/d95adf6eef414a7396edf2c9accba39e.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), 'ab265e8442124d87afdfe3a44e84e75c', 'https://media.liche.cn/meijiaka-zy/materials/ab265e8442124d87afdfe3a44e84e75c.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'f6141378dacc4547831905162cef55d6', 'https://media.liche.cn/meijiaka-zy/materials/f6141378dacc4547831905162cef55d6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '7866a9d67f7b4c19b2150cca0bae9921', 'https://media.liche.cn/meijiaka-zy/materials/7866a9d67f7b4c19b2150cca0bae9921.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '0ad8580b062045a49eb4a9b48f81f0c2', 'https://media.liche.cn/meijiaka-zy/materials/0ad8580b062045a49eb4a9b48f81f0c2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '1b0c5bd3e31f407fbd432899a11213ca', 'https://media.liche.cn/meijiaka-zy/materials/1b0c5bd3e31f407fbd432899a11213ca.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '8f262e2bf8af45ce9f6659ebb94ee034', 'https://media.liche.cn/meijiaka-zy/materials/8f262e2bf8af45ce9f6659ebb94ee034.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆不要买贵的' AND level = 3), '16baa1a59a934cdba39a1a359c79d7da', 'https://media.liche.cn/meijiaka-zy/materials/16baa1a59a934cdba39a1a359c79d7da.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'e317189eeab34e8a8de23384b1aa87f7', 'https://media.liche.cn/meijiaka-zy/materials/e317189eeab34e8a8de23384b1aa87f7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '6c4b5a7489fc4c3cb79d9d02eea37741', 'https://media.liche.cn/meijiaka-zy/materials/6c4b5a7489fc4c3cb79d9d02eea37741.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '9a5e862f10c546a4baad0e23a7aa380f', 'https://media.liche.cn/meijiaka-zy/materials/9a5e862f10c546a4baad0e23a7aa380f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'ccb739146d084d5a91d1e9988d0c9bc2', 'https://media.liche.cn/meijiaka-zy/materials/ccb739146d084d5a91d1e9988d0c9bc2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'c2db3ede0c2e4a7a8186851b2741d88b', 'https://media.liche.cn/meijiaka-zy/materials/c2db3ede0c2e4a7a8186851b2741d88b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '50c7a68f700647f0a71765db8a797e5f', 'https://media.liche.cn/meijiaka-zy/materials/50c7a68f700647f0a71765db8a797e5f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '69441b13cbf34a39bd712229ebe106a9', 'https://media.liche.cn/meijiaka-zy/materials/69441b13cbf34a39bd712229ebe106a9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '3ce1a2d7a63f458ba3ee1cba1f217804', 'https://media.liche.cn/meijiaka-zy/materials/3ce1a2d7a63f458ba3ee1cba1f217804.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'af31e4be297942d2823fef869e31883a', 'https://media.liche.cn/meijiaka-zy/materials/af31e4be297942d2823fef869e31883a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'ee3a24dce34a4e69831a7f848d96b871', 'https://media.liche.cn/meijiaka-zy/materials/ee3a24dce34a4e69831a7f848d96b871.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'e39b3f1d77c14925912283e12650207b', 'https://media.liche.cn/meijiaka-zy/materials/e39b3f1d77c14925912283e12650207b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'c987ba26f25c4f69bf9f25688754f96a', 'https://media.liche.cn/meijiaka-zy/materials/c987ba26f25c4f69bf9f25688754f96a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'ecc69808f87549768ee24eafa321c8ae', 'https://media.liche.cn/meijiaka-zy/materials/ecc69808f87549768ee24eafa321c8ae.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '7af06717ce91433bb281ccaf6fda30a6', 'https://media.liche.cn/meijiaka-zy/materials/7af06717ce91433bb281ccaf6fda30a6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'cb494108ec9b4814a751115e8990a310', 'https://media.liche.cn/meijiaka-zy/materials/cb494108ec9b4814a751115e8990a310.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '66f7e39f4c8448c4af181edcb8504c83', 'https://media.liche.cn/meijiaka-zy/materials/66f7e39f4c8448c4af181edcb8504c83.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '502d99c560b147eab69590972a3cdc14', 'https://media.liche.cn/meijiaka-zy/materials/502d99c560b147eab69590972a3cdc14.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '7cfa80ff67b544089179dc626c481385', 'https://media.liche.cn/meijiaka-zy/materials/7cfa80ff67b544089179dc626c481385.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '5fcb58f0684a404aabb4b809bccb2302', 'https://media.liche.cn/meijiaka-zy/materials/5fcb58f0684a404aabb4b809bccb2302.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '17bab2c61eec45b1beb6ba617beb0b8c', 'https://media.liche.cn/meijiaka-zy/materials/17bab2c61eec45b1beb6ba617beb0b8c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '2adc1289ecb542a49abd1b4049f81dea', 'https://media.liche.cn/meijiaka-zy/materials/2adc1289ecb542a49abd1b4049f81dea.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '70698d8b574f4001a4c583d18b61fbb0', 'https://media.liche.cn/meijiaka-zy/materials/70698d8b574f4001a4c583d18b61fbb0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'fb108e5fbf394487b5d203ecc58422d7', 'https://media.liche.cn/meijiaka-zy/materials/fb108e5fbf394487b5d203ecc58422d7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '0b7d0d28a35842a7b8d2e6d175b4fa55', 'https://media.liche.cn/meijiaka-zy/materials/0b7d0d28a35842a7b8d2e6d175b4fa55.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '2de94484f98d464d8f71c027ac36ff80', 'https://media.liche.cn/meijiaka-zy/materials/2de94484f98d464d8f71c027ac36ff80.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'be38e502cc284b1fbae247e79c5ff62a', 'https://media.liche.cn/meijiaka-zy/materials/be38e502cc284b1fbae247e79c5ff62a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'af055b038ce34bff9cffc144a973c608', 'https://media.liche.cn/meijiaka-zy/materials/af055b038ce34bff9cffc144a973c608.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '3200e511c3c94b7ead4e5fe9dc95b4d3', 'https://media.liche.cn/meijiaka-zy/materials/3200e511c3c94b7ead4e5fe9dc95b4d3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'a0a365ec78084927b05f3653e8ba4f90', 'https://media.liche.cn/meijiaka-zy/materials/a0a365ec78084927b05f3653e8ba4f90.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '2c11321dfdd048baaa3c0c8953259f3d', 'https://media.liche.cn/meijiaka-zy/materials/2c11321dfdd048baaa3c0c8953259f3d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '85024cedb75f4580bfd4982e6d8c745a', 'https://media.liche.cn/meijiaka-zy/materials/85024cedb75f4580bfd4982e6d8c745a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), '3e7e583dc37240418e6152c7cc1b787b', 'https://media.liche.cn/meijiaka-zy/materials/3e7e583dc37240418e6152c7cc1b787b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'efc0c02d3ac14f58862d435ff12dcc96', 'https://media.liche.cn/meijiaka-zy/materials/efc0c02d3ac14f58862d435ff12dcc96.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木门不要买贵的' AND level = 3), 'adf854bfb8654d5ea81e81bec1ca5f02', 'https://media.liche.cn/meijiaka-zy/materials/adf854bfb8654d5ea81e81bec1ca5f02.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '033d0bfcfc774d1396005536da0d26d0', 'https://media.liche.cn/meijiaka-zy/materials/033d0bfcfc774d1396005536da0d26d0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '188647393cdf4a838064ee3ed1f73eaa', 'https://media.liche.cn/meijiaka-zy/materials/188647393cdf4a838064ee3ed1f73eaa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '6255fc2628954c8fbed4b7ea1d999256', 'https://media.liche.cn/meijiaka-zy/materials/6255fc2628954c8fbed4b7ea1d999256.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'e608ef48ad0c4afdafa47cbd65e9dc30', 'https://media.liche.cn/meijiaka-zy/materials/e608ef48ad0c4afdafa47cbd65e9dc30.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '52b845a5dae24e39a26211b4f4707a0b', 'https://media.liche.cn/meijiaka-zy/materials/52b845a5dae24e39a26211b4f4707a0b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '3152786dd883492783061a1aa4ef6107', 'https://media.liche.cn/meijiaka-zy/materials/3152786dd883492783061a1aa4ef6107.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'fe58e4b5457c456490fdf2907d35d0f9', 'https://media.liche.cn/meijiaka-zy/materials/fe58e4b5457c456490fdf2907d35d0f9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '33912de40e684f2f934d5e1dafd3b707', 'https://media.liche.cn/meijiaka-zy/materials/33912de40e684f2f934d5e1dafd3b707.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'dad9447bdafc4b228b91e5c6913b764b', 'https://media.liche.cn/meijiaka-zy/materials/dad9447bdafc4b228b91e5c6913b764b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '161b5fd33c2c4ddd9c4dd7879184a46f', 'https://media.liche.cn/meijiaka-zy/materials/161b5fd33c2c4ddd9c4dd7879184a46f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '2d8ae1db23c34325941f3067553d6d62', 'https://media.liche.cn/meijiaka-zy/materials/2d8ae1db23c34325941f3067553d6d62.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '83d90bae87294a23b96babecc45df9db', 'https://media.liche.cn/meijiaka-zy/materials/83d90bae87294a23b96babecc45df9db.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'a8911b2854db44dfa30234807b7286d7', 'https://media.liche.cn/meijiaka-zy/materials/a8911b2854db44dfa30234807b7286d7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '24b5742c900640409399fdc9ba293163', 'https://media.liche.cn/meijiaka-zy/materials/24b5742c900640409399fdc9ba293163.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '2e1c93ea02734680a3066ed743a4643d', 'https://media.liche.cn/meijiaka-zy/materials/2e1c93ea02734680a3066ed743a4643d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'a1363c13c7b54002b455c26ea02630dd', 'https://media.liche.cn/meijiaka-zy/materials/a1363c13c7b54002b455c26ea02630dd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), 'f1ea2227caa242a89d0c5c68d5446ce1', 'https://media.liche.cn/meijiaka-zy/materials/f1ea2227caa242a89d0c5c68d5446ce1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '385e3e06e3794c1b86c87819553d22c1', 'https://media.liche.cn/meijiaka-zy/materials/385e3e06e3794c1b86c87819553d22c1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '8b20d430140e41b7b48824712cfa7657', 'https://media.liche.cn/meijiaka-zy/materials/8b20d430140e41b7b48824712cfa7657.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '5a1b7a63ebd1467a85f0206d710a7a79', 'https://media.liche.cn/meijiaka-zy/materials/5a1b7a63ebd1467a85f0206d710a7a79.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '51d589d83faf494aaadf9e61448e6e34', 'https://media.liche.cn/meijiaka-zy/materials/51d589d83faf494aaadf9e61448e6e34.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '70d33bbe4fff4e16a61a802d8e432f9e', 'https://media.liche.cn/meijiaka-zy/materials/70d33bbe4fff4e16a61a802d8e432f9e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '416402b79dfc473d9500583c091eb78e', 'https://media.liche.cn/meijiaka-zy/materials/416402b79dfc473d9500583c091eb78e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '窗帘不要买贵的' AND level = 3), '15c9b4083cc34f44a0bedc961a3e9101', 'https://media.liche.cn/meijiaka-zy/materials/15c9b4083cc34f44a0bedc961a3e9101.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '4ee53896aa134b76944a0680afa90ada', 'https://media.liche.cn/meijiaka-zy/materials/4ee53896aa134b76944a0680afa90ada.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '607d1ab5c3ab4e6ebd9de0d2e413a07d', 'https://media.liche.cn/meijiaka-zy/materials/607d1ab5c3ab4e6ebd9de0d2e413a07d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'b303093963ab499ea4e3ef8de95b0432', 'https://media.liche.cn/meijiaka-zy/materials/b303093963ab499ea4e3ef8de95b0432.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'dc09baf7255646ae84b4835887f50c48', 'https://media.liche.cn/meijiaka-zy/materials/dc09baf7255646ae84b4835887f50c48.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '9ae7a9a54dbe476ba2d99a6628350a2a', 'https://media.liche.cn/meijiaka-zy/materials/9ae7a9a54dbe476ba2d99a6628350a2a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '244543933ea6458394aad01e14035d26', 'https://media.liche.cn/meijiaka-zy/materials/244543933ea6458394aad01e14035d26.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '0d6cdf4bd1664ea58c50c7e284de9517', 'https://media.liche.cn/meijiaka-zy/materials/0d6cdf4bd1664ea58c50c7e284de9517.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '5fdb7bdc44f24cdcaa91abe5e64b0ef6', 'https://media.liche.cn/meijiaka-zy/materials/5fdb7bdc44f24cdcaa91abe5e64b0ef6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '0624c0be62774c819abffce08e2ec551', 'https://media.liche.cn/meijiaka-zy/materials/0624c0be62774c819abffce08e2ec551.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'e0424b6c0d3c4ff9b24c9df64ea24821', 'https://media.liche.cn/meijiaka-zy/materials/e0424b6c0d3c4ff9b24c9df64ea24821.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'cac8ba096d3349b1a37fd136201ff044', 'https://media.liche.cn/meijiaka-zy/materials/cac8ba096d3349b1a37fd136201ff044.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '356bbe4534d94bc6829c625499b55ab3', 'https://media.liche.cn/meijiaka-zy/materials/356bbe4534d94bc6829c625499b55ab3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '87977b6a1c914f1aaa504d20fe90bb17', 'https://media.liche.cn/meijiaka-zy/materials/87977b6a1c914f1aaa504d20fe90bb17.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '40a8b86caa43498db139f2543f71dc72', 'https://media.liche.cn/meijiaka-zy/materials/40a8b86caa43498db139f2543f71dc72.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'c709ac91b83748db8a56e286f6593d32', 'https://media.liche.cn/meijiaka-zy/materials/c709ac91b83748db8a56e286f6593d32.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '2ea71b7ca2e340289be3ae071cbeb683', 'https://media.liche.cn/meijiaka-zy/materials/2ea71b7ca2e340289be3ae071cbeb683.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '728c5b266e2e4efab93cf36366be228f', 'https://media.liche.cn/meijiaka-zy/materials/728c5b266e2e4efab93cf36366be228f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '227f9e77442d4acdb712d7e9d782760e', 'https://media.liche.cn/meijiaka-zy/materials/227f9e77442d4acdb712d7e9d782760e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'dbf42cac44384de18706b9aeca4dcfdd', 'https://media.liche.cn/meijiaka-zy/materials/dbf42cac44384de18706b9aeca4dcfdd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'ae4da22db8474d98b67bf758576ccb07', 'https://media.liche.cn/meijiaka-zy/materials/ae4da22db8474d98b67bf758576ccb07.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '82cd342317084066be7c122738b9163b', 'https://media.liche.cn/meijiaka-zy/materials/82cd342317084066be7c122738b9163b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '0bff59808dd94b37a894f6617a71932e', 'https://media.liche.cn/meijiaka-zy/materials/0bff59808dd94b37a894f6617a71932e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), 'bfa3e9cb10a149f19810b2df48e04ea8', 'https://media.liche.cn/meijiaka-zy/materials/bfa3e9cb10a149f19810b2df48e04ea8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '89325b7d7bb94010aef0ff9d44a51fb4', 'https://media.liche.cn/meijiaka-zy/materials/89325b7d7bb94010aef0ff9d44a51fb4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '76bc4ae2764a4bfcab7615af2a458f46', 'https://media.liche.cn/meijiaka-zy/materials/76bc4ae2764a4bfcab7615af2a458f46.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'b4128f8850014c929eb1844de5817877', 'https://media.liche.cn/meijiaka-zy/materials/b4128f8850014c929eb1844de5817877.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '13e5190ee3264511b2e954c43d0a93ed', 'https://media.liche.cn/meijiaka-zy/materials/13e5190ee3264511b2e954c43d0a93ed.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '773d73bccd8d4295bf33d5f6fa179f00', 'https://media.liche.cn/meijiaka-zy/materials/773d73bccd8d4295bf33d5f6fa179f00.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '25dbdfc95bbd4c5fb4538a89580300cc', 'https://media.liche.cn/meijiaka-zy/materials/25dbdfc95bbd4c5fb4538a89580300cc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '017b3f77ceaf47f6a123a3d2d67d0cb5', 'https://media.liche.cn/meijiaka-zy/materials/017b3f77ceaf47f6a123a3d2d67d0cb5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水槽不要买贵的' AND level = 3), '6013a7e2150f46f19533b8e0978e8be9', 'https://media.liche.cn/meijiaka-zy/materials/6013a7e2150f46f19533b8e0978e8be9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'b774f8dc575646f199cd9b36740d3844', 'https://media.liche.cn/meijiaka-zy/materials/b774f8dc575646f199cd9b36740d3844.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '275c8254ab1e493ca9e0541d61df3365', 'https://media.liche.cn/meijiaka-zy/materials/275c8254ab1e493ca9e0541d61df3365.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '753f2a0452f642738d94d8f81f99944f', 'https://media.liche.cn/meijiaka-zy/materials/753f2a0452f642738d94d8f81f99944f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'd42af2e5587e4782bd9a5e3d4ae1bd7a', 'https://media.liche.cn/meijiaka-zy/materials/d42af2e5587e4782bd9a5e3d4ae1bd7a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '0746a4492e0849d996015b40218f6bbe', 'https://media.liche.cn/meijiaka-zy/materials/0746a4492e0849d996015b40218f6bbe.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'f4a13a9468f243b7bcfc11ec3371a049', 'https://media.liche.cn/meijiaka-zy/materials/f4a13a9468f243b7bcfc11ec3371a049.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'f714ef94c20a411a8c1f2fa6a9db09b1', 'https://media.liche.cn/meijiaka-zy/materials/f714ef94c20a411a8c1f2fa6a9db09b1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '11b72bcb5b9e4be8aab98f18d01813b7', 'https://media.liche.cn/meijiaka-zy/materials/11b72bcb5b9e4be8aab98f18d01813b7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'efb21ed9b9754795baec6bcf7a8e68dc', 'https://media.liche.cn/meijiaka-zy/materials/efb21ed9b9754795baec6bcf7a8e68dc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '42d2b1fa3d6841e6b17ede794a386989', 'https://media.liche.cn/meijiaka-zy/materials/42d2b1fa3d6841e6b17ede794a386989.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'b6d83dfc6464461db4fc72f86260cb3d', 'https://media.liche.cn/meijiaka-zy/materials/b6d83dfc6464461db4fc72f86260cb3d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '45aaa326b4234819a42555c0f7b6a621', 'https://media.liche.cn/meijiaka-zy/materials/45aaa326b4234819a42555c0f7b6a621.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '692a2e0e03454ec1a2ce2ab6fbb8a1aa', 'https://media.liche.cn/meijiaka-zy/materials/692a2e0e03454ec1a2ce2ab6fbb8a1aa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '56f47ed6c7564af39f6d84f2d40f4988', 'https://media.liche.cn/meijiaka-zy/materials/56f47ed6c7564af39f6d84f2d40f4988.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '43d3fb9deb0b4ca18ea4b59523bba900', 'https://media.liche.cn/meijiaka-zy/materials/43d3fb9deb0b4ca18ea4b59523bba900.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '96b35e39f7574965b1c17554f02dbb8c', 'https://media.liche.cn/meijiaka-zy/materials/96b35e39f7574965b1c17554f02dbb8c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'ed55a7de9abb4b49a8cb9636c0c6c61e', 'https://media.liche.cn/meijiaka-zy/materials/ed55a7de9abb4b49a8cb9636c0c6c61e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '4ad3e758f778442eb7d0c8a6cf4fc015', 'https://media.liche.cn/meijiaka-zy/materials/4ad3e758f778442eb7d0c8a6cf4fc015.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '452fc6fcc977464b887a731457c1b066', 'https://media.liche.cn/meijiaka-zy/materials/452fc6fcc977464b887a731457c1b066.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '7893362bdd38454f8927e0fd9f861fc5', 'https://media.liche.cn/meijiaka-zy/materials/7893362bdd38454f8927e0fd9f861fc5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'd6cd6efff3244736a4c970d0758f4785', 'https://media.liche.cn/meijiaka-zy/materials/d6cd6efff3244736a4c970d0758f4785.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '1365d9242c854b1b9dfd9bfa00d10120', 'https://media.liche.cn/meijiaka-zy/materials/1365d9242c854b1b9dfd9bfa00d10120.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '416d5c87174d4c14a85bdf663bf069de', 'https://media.liche.cn/meijiaka-zy/materials/416d5c87174d4c14a85bdf663bf069de.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'f6ed8d38ebbc46f8bb5a5c54e02afa08', 'https://media.liche.cn/meijiaka-zy/materials/f6ed8d38ebbc46f8bb5a5c54e02afa08.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '3d094410ed8943a1bde21c209c2f64b7', 'https://media.liche.cn/meijiaka-zy/materials/3d094410ed8943a1bde21c209c2f64b7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'addaa36a72764179868330bf7ed5a7ba', 'https://media.liche.cn/meijiaka-zy/materials/addaa36a72764179868330bf7ed5a7ba.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), 'ba5c781956164ac58180c29b261735eb', 'https://media.liche.cn/meijiaka-zy/materials/ba5c781956164ac58180c29b261735eb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '6866fa1f41364078bec24a5722bb33c6', 'https://media.liche.cn/meijiaka-zy/materials/6866fa1f41364078bec24a5722bb33c6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '1cb0a59f37fb47d29f18631ff891a6e4', 'https://media.liche.cn/meijiaka-zy/materials/1cb0a59f37fb47d29f18631ff891a6e4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '6e207e874eb6482abfe15b04ac1f12cf', 'https://media.liche.cn/meijiaka-zy/materials/6e207e874eb6482abfe15b04ac1f12cf.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '木地板要买贵的' AND level = 3), '9486b9e6b090450fb8166cf4fd172929', 'https://media.liche.cn/meijiaka-zy/materials/9486b9e6b090450fb8166cf4fd172929.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'd347b3830e6e43238662a93788e00441', 'https://media.liche.cn/meijiaka-zy/materials/d347b3830e6e43238662a93788e00441.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'fc973d800cc24f5981f890c4ab7c5a53', 'https://media.liche.cn/meijiaka-zy/materials/fc973d800cc24f5981f890c4ab7c5a53.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '446e74d0fe9c45c18abb73f428ef2a1d', 'https://media.liche.cn/meijiaka-zy/materials/446e74d0fe9c45c18abb73f428ef2a1d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '7844b1ba14c847a18da48128811d6648', 'https://media.liche.cn/meijiaka-zy/materials/7844b1ba14c847a18da48128811d6648.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'd827b939e8f749e0afd438d0fd3582d5', 'https://media.liche.cn/meijiaka-zy/materials/d827b939e8f749e0afd438d0fd3582d5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '6c445666e4e44e5d8bb51d455c4fef80', 'https://media.liche.cn/meijiaka-zy/materials/6c445666e4e44e5d8bb51d455c4fef80.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '4fec87633bea40bfa2f3814ba98e20de', 'https://media.liche.cn/meijiaka-zy/materials/4fec87633bea40bfa2f3814ba98e20de.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '1bb41138c4364cf2afdff143d3921461', 'https://media.liche.cn/meijiaka-zy/materials/1bb41138c4364cf2afdff143d3921461.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '4388d9790c24423fa680d19e78711ffe', 'https://media.liche.cn/meijiaka-zy/materials/4388d9790c24423fa680d19e78711ffe.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '955a15625bf24447802765c8dea0dab0', 'https://media.liche.cn/meijiaka-zy/materials/955a15625bf24447802765c8dea0dab0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '25c0be5f812c40c9b6c1b012a5d41c6e', 'https://media.liche.cn/meijiaka-zy/materials/25c0be5f812c40c9b6c1b012a5d41c6e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '4b542ed582224750868822e9a5b66d2f', 'https://media.liche.cn/meijiaka-zy/materials/4b542ed582224750868822e9a5b66d2f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'e49e88f72de54583a61200888c806228', 'https://media.liche.cn/meijiaka-zy/materials/e49e88f72de54583a61200888c806228.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'd3708dab5eca417789661c6bd8954237', 'https://media.liche.cn/meijiaka-zy/materials/d3708dab5eca417789661c6bd8954237.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'ab6ad655811e4ec4b8d49aa40cedc92f', 'https://media.liche.cn/meijiaka-zy/materials/ab6ad655811e4ec4b8d49aa40cedc92f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '92f988dd18f04e589a7c2029c04e2497', 'https://media.liche.cn/meijiaka-zy/materials/92f988dd18f04e589a7c2029c04e2497.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '5379a5d3b432426d88fad5e1feb9bf8d', 'https://media.liche.cn/meijiaka-zy/materials/5379a5d3b432426d88fad5e1feb9bf8d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '62ec2f25e4d945d28eec88cc0958f4e9', 'https://media.liche.cn/meijiaka-zy/materials/62ec2f25e4d945d28eec88cc0958f4e9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '8c503dbb83404e0b87c2a5688efd64fd', 'https://media.liche.cn/meijiaka-zy/materials/8c503dbb83404e0b87c2a5688efd64fd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '2bfe8997f75e4881ac4166b828a92c57', 'https://media.liche.cn/meijiaka-zy/materials/2bfe8997f75e4881ac4166b828a92c57.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'abb5526452f744bf808eb79f8c960142', 'https://media.liche.cn/meijiaka-zy/materials/abb5526452f744bf808eb79f8c960142.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '1bd3b186207f401c8023616f662e56a8', 'https://media.liche.cn/meijiaka-zy/materials/1bd3b186207f401c8023616f662e56a8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '593ef1d61a914edaa54a96f65a54423e', 'https://media.liche.cn/meijiaka-zy/materials/593ef1d61a914edaa54a96f65a54423e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'daa623f9f2e84d86aaa24b4aea9d6499', 'https://media.liche.cn/meijiaka-zy/materials/daa623f9f2e84d86aaa24b4aea9d6499.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '9d93e1cbd1b24eb0ab6abc419eb91e3d', 'https://media.liche.cn/meijiaka-zy/materials/9d93e1cbd1b24eb0ab6abc419eb91e3d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '56e39dacb7d34ed8afed2b40c4dd993f', 'https://media.liche.cn/meijiaka-zy/materials/56e39dacb7d34ed8afed2b40c4dd993f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '566d6bf1862d427ba6e6f925eceaab6d', 'https://media.liche.cn/meijiaka-zy/materials/566d6bf1862d427ba6e6f925eceaab6d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'fc8d6eb3fd1b429bab08049d3c8a1eb8', 'https://media.liche.cn/meijiaka-zy/materials/fc8d6eb3fd1b429bab08049d3c8a1eb8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '165c6b31d9bc40e1a141ddfb0056a3da', 'https://media.liche.cn/meijiaka-zy/materials/165c6b31d9bc40e1a141ddfb0056a3da.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '57b204c634ae4b0bb4410c855c38c9a0', 'https://media.liche.cn/meijiaka-zy/materials/57b204c634ae4b0bb4410c855c38c9a0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '36cbd4bf0b874c4a90cef6bdb7c17bf8', 'https://media.liche.cn/meijiaka-zy/materials/36cbd4bf0b874c4a90cef6bdb7c17bf8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '22f8bd01f6a8403c8fe895aec659c52c', 'https://media.liche.cn/meijiaka-zy/materials/22f8bd01f6a8403c8fe895aec659c52c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '4e731f60d3fb4962bd579c6350af822a', 'https://media.liche.cn/meijiaka-zy/materials/4e731f60d3fb4962bd579c6350af822a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '6733ed366ad14bcbac548dab3d5dd393', 'https://media.liche.cn/meijiaka-zy/materials/6733ed366ad14bcbac548dab3d5dd393.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), '5e21c9abd4bb43519004e21aa7046c39', 'https://media.liche.cn/meijiaka-zy/materials/5e21c9abd4bb43519004e21aa7046c39.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'bca07a5ec1ec4c56a5bdf6c17f6fab48', 'https://media.liche.cn/meijiaka-zy/materials/bca07a5ec1ec4c56a5bdf6c17f6fab48.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'cff3ace3c7184a3ab27929fcec7cf206', 'https://media.liche.cn/meijiaka-zy/materials/cff3ace3c7184a3ab27929fcec7cf206.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'f39f7166ec084b4481385da2d4591dc3', 'https://media.liche.cn/meijiaka-zy/materials/f39f7166ec084b4481385da2d4591dc3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'ab16c79e67584a6bb364d7aa8ebf5e16', 'https://media.liche.cn/meijiaka-zy/materials/ab16c79e67584a6bb364d7aa8ebf5e16.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'f956b8946836499caf13a868c59d13e7', 'https://media.liche.cn/meijiaka-zy/materials/f956b8946836499caf13a868c59d13e7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖不要买贵的' AND level = 3), 'd710afdb69554d7cacf5652554c7500b', 'https://media.liche.cn/meijiaka-zy/materials/d710afdb69554d7cacf5652554c7500b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), '35984cffb2e04c628afd42289727b275', 'https://media.liche.cn/meijiaka-zy/materials/35984cffb2e04c628afd42289727b275.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), '8335b7ebe80e411b8ebe674094d6c758', 'https://media.liche.cn/meijiaka-zy/materials/8335b7ebe80e411b8ebe674094d6c758.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), '044388f09bf8494794942c52dac8991b', 'https://media.liche.cn/meijiaka-zy/materials/044388f09bf8494794942c52dac8991b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'b9c18b2175614f3298f1dd77b0d25c6f', 'https://media.liche.cn/meijiaka-zy/materials/b9c18b2175614f3298f1dd77b0d25c6f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'd9ee8df1da3944978ac102c0dbe6d64e', 'https://media.liche.cn/meijiaka-zy/materials/d9ee8df1da3944978ac102c0dbe6d64e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'e769cbf69306444fb9c3971cfe9d1c3b', 'https://media.liche.cn/meijiaka-zy/materials/e769cbf69306444fb9c3971cfe9d1c3b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), '6e3e0ab4fb744022a5346a7c72d697c0', 'https://media.liche.cn/meijiaka-zy/materials/6e3e0ab4fb744022a5346a7c72d697c0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'b59c4a2025f4407db49342fcda757b50', 'https://media.liche.cn/meijiaka-zy/materials/b59c4a2025f4407db49342fcda757b50.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'ff858916850f4d70aa3411b349f2ffa9', 'https://media.liche.cn/meijiaka-zy/materials/ff858916850f4d70aa3411b349f2ffa9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '29337b97734e4b44bce3f1f5f47a8ffa', 'https://media.liche.cn/meijiaka-zy/materials/29337b97734e4b44bce3f1f5f47a8ffa.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '4e0c801ff7de46dfb388a41134c7d38d', 'https://media.liche.cn/meijiaka-zy/materials/4e0c801ff7de46dfb388a41134c7d38d.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), 'a46032f0d157408d9d58106bffa6e8dd', 'https://media.liche.cn/meijiaka-zy/materials/a46032f0d157408d9d58106bffa6e8dd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '70ac7dc414de4e42a92bf5d6d87c4b0e', 'https://media.liche.cn/meijiaka-zy/materials/70ac7dc414de4e42a92bf5d6d87c4b0e.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '077879551aa44ffabdf0458c2ddc53d7', 'https://media.liche.cn/meijiaka-zy/materials/077879551aa44ffabdf0458c2ddc53d7.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'f887906a51d3467caed8edbaeaf6f0ba', 'https://media.liche.cn/meijiaka-zy/materials/f887906a51d3467caed8edbaeaf6f0ba.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '309b0e64ff3b4f37b0d42f9a6f1c1995', 'https://media.liche.cn/meijiaka-zy/materials/309b0e64ff3b4f37b0d42f9a6f1c1995.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '全屋角阀要买贵的' AND level = 3), '430cc9b8a54848fcb37fdde66f9a039e', 'https://media.liche.cn/meijiaka-zy/materials/430cc9b8a54848fcb37fdde66f9a039e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'd85d298de22341f6bcad72dec3437a54', 'https://media.liche.cn/meijiaka-zy/materials/d85d298de22341f6bcad72dec3437a54.mp4', 0.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'bcded59c41aa40e8afa3adc3423ebc21', 'https://media.liche.cn/meijiaka-zy/materials/bcded59c41aa40e8afa3adc3423ebc21.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '20025f6afdbf4b8cbd4776fb89b67271', 'https://media.liche.cn/meijiaka-zy/materials/20025f6afdbf4b8cbd4776fb89b67271.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'bad2b7316a89433092debe07823de4c9', 'https://media.liche.cn/meijiaka-zy/materials/bad2b7316a89433092debe07823de4c9.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '7e610c5316a44e4c865be92409d0e3df', 'https://media.liche.cn/meijiaka-zy/materials/7e610c5316a44e4c865be92409d0e3df.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '996b350237c7494084eb8d269f065a84', 'https://media.liche.cn/meijiaka-zy/materials/996b350237c7494084eb8d269f065a84.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'f7404804cd4f4dd780283c00cc3c73c1', 'https://media.liche.cn/meijiaka-zy/materials/f7404804cd4f4dd780283c00cc3c73c1.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '6fcbb533b5b8488fb5ad3d45ded7d618', 'https://media.liche.cn/meijiaka-zy/materials/6fcbb533b5b8488fb5ad3d45ded7d618.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), 'cdd6f245a1234cb3890fefe1fba73ace', 'https://media.liche.cn/meijiaka-zy/materials/cdd6f245a1234cb3890fefe1fba73ace.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '9fa4f468e8e3481ab3f36990f56ebfc2', 'https://media.liche.cn/meijiaka-zy/materials/9fa4f468e8e3481ab3f36990f56ebfc2.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '2681adbd691d4866abfe8bf5dd5880ba', 'https://media.liche.cn/meijiaka-zy/materials/2681adbd691d4866abfe8bf5dd5880ba.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '96abdacb9c2e414f8c058ad559c95293', 'https://media.liche.cn/meijiaka-zy/materials/96abdacb9c2e414f8c058ad559c95293.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '35b45c67ae6244df91b152ec28bb060e', 'https://media.liche.cn/meijiaka-zy/materials/35b45c67ae6244df91b152ec28bb060e.mp4', 3.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '7763fb8533bb4b6b8ca38fd9796f0dc5', 'https://media.liche.cn/meijiaka-zy/materials/7763fb8533bb4b6b8ca38fd9796f0dc5.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '床垫要买贵的' AND level = 3), '629b674e8a7f45dd81419162ce17b4e8', 'https://media.liche.cn/meijiaka-zy/materials/629b674e8a7f45dd81419162ce17b4e8.mp4', 3.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'c42732a53c374397a34f1bd5e94ebe40', 'https://media.liche.cn/meijiaka-zy/materials/c42732a53c374397a34f1bd5e94ebe40.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'd8e11ee1fffe43ee9ff9b267e91ef844', 'https://media.liche.cn/meijiaka-zy/materials/d8e11ee1fffe43ee9ff9b267e91ef844.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'c53bc2d216ca4dc48a89c2ad7c6fbc95', 'https://media.liche.cn/meijiaka-zy/materials/c53bc2d216ca4dc48a89c2ad7c6fbc95.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '232a82e3ffac4b719d9d06bcd81629b8', 'https://media.liche.cn/meijiaka-zy/materials/232a82e3ffac4b719d9d06bcd81629b8.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '12176f60c2434e8aa971f9c9eb4e6644', 'https://media.liche.cn/meijiaka-zy/materials/12176f60c2434e8aa971f9c9eb4e6644.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '426c1c2b6f054562a04bc927398b388e', 'https://media.liche.cn/meijiaka-zy/materials/426c1c2b6f054562a04bc927398b388e.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '8e96d1cdbee946e0a164f3d0dee1ad2e', 'https://media.liche.cn/meijiaka-zy/materials/8e96d1cdbee946e0a164f3d0dee1ad2e.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '1528a0e6d1d04f11a1a08e9f0a3a0d44', 'https://media.liche.cn/meijiaka-zy/materials/1528a0e6d1d04f11a1a08e9f0a3a0d44.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'c651d39ea5454924bf0822e048b2aff2', 'https://media.liche.cn/meijiaka-zy/materials/c651d39ea5454924bf0822e048b2aff2.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '853ead5926aa40aebe90ff8370f878f9', 'https://media.liche.cn/meijiaka-zy/materials/853ead5926aa40aebe90ff8370f878f9.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'cc0147af74be4013a146ff1c1179d669', 'https://media.liche.cn/meijiaka-zy/materials/cc0147af74be4013a146ff1c1179d669.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '6972a8db7aff48358bcb53b7fb08e228', 'https://media.liche.cn/meijiaka-zy/materials/6972a8db7aff48358bcb53b7fb08e228.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '5b13c4a96edd4a1d9d9dd70c84ed2b66', 'https://media.liche.cn/meijiaka-zy/materials/5b13c4a96edd4a1d9d9dd70c84ed2b66.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'a761830e75874f6abb49dc5f5ada3cdc', 'https://media.liche.cn/meijiaka-zy/materials/a761830e75874f6abb49dc5f5ada3cdc.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '22c01d1dbe814eecafcfbecfd6e670f9', 'https://media.liche.cn/meijiaka-zy/materials/22c01d1dbe814eecafcfbecfd6e670f9.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '8b8472bee2d9430598c2c0ca53271ecb', 'https://media.liche.cn/meijiaka-zy/materials/8b8472bee2d9430598c2c0ca53271ecb.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'b787ee5d82c64de1aa1a4eb3c1ae9688', 'https://media.liche.cn/meijiaka-zy/materials/b787ee5d82c64de1aa1a4eb3c1ae9688.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '5729801590974cc5a9f85f2e5ea1405b', 'https://media.liche.cn/meijiaka-zy/materials/5729801590974cc5a9f85f2e5ea1405b.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'c7833075f28c485cb01b180c1378c6c7', 'https://media.liche.cn/meijiaka-zy/materials/c7833075f28c485cb01b180c1378c6c7.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '4421f66dd2e7417e9d7876b13f679928', 'https://media.liche.cn/meijiaka-zy/materials/4421f66dd2e7417e9d7876b13f679928.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '9daae1d4189844c49c28163b2f03071d', 'https://media.liche.cn/meijiaka-zy/materials/9daae1d4189844c49c28163b2f03071d.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'c9ae6bac766a4dde9a66b3330d4340c3', 'https://media.liche.cn/meijiaka-zy/materials/c9ae6bac766a4dde9a66b3330d4340c3.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'd3859601f1104d198424c230fb1c9613', 'https://media.liche.cn/meijiaka-zy/materials/d3859601f1104d198424c230fb1c9613.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '4f986799c301475f905b8d95d48f6aac', 'https://media.liche.cn/meijiaka-zy/materials/4f986799c301475f905b8d95d48f6aac.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '3bf4c1f33813438ca4b30fec8684443b', 'https://media.liche.cn/meijiaka-zy/materials/3bf4c1f33813438ca4b30fec8684443b.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '65846e9df8bf4b55a1c808b07e6da0f7', 'https://media.liche.cn/meijiaka-zy/materials/65846e9df8bf4b55a1c808b07e6da0f7.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '21f619fd7a9744afb361a6419a5b9337', 'https://media.liche.cn/meijiaka-zy/materials/21f619fd7a9744afb361a6419a5b9337.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '290e9f1fe50a47d2b15fc02612a36635', 'https://media.liche.cn/meijiaka-zy/materials/290e9f1fe50a47d2b15fc02612a36635.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '56657f4653f743a3ac93a0d9d02d132f', 'https://media.liche.cn/meijiaka-zy/materials/56657f4653f743a3ac93a0d9d02d132f.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '07397f0bb63e462f8d3fd4dcbbd5de7f', 'https://media.liche.cn/meijiaka-zy/materials/07397f0bb63e462f8d3fd4dcbbd5de7f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '3719c1806c94445a9c8066260f4f9870', 'https://media.liche.cn/meijiaka-zy/materials/3719c1806c94445a9c8066260f4f9870.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '33a1a3a3a09f45f0a5206a7297ae341a', 'https://media.liche.cn/meijiaka-zy/materials/33a1a3a3a09f45f0a5206a7297ae341a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'a5e4120cbf4a401c88aee857b92b156d', 'https://media.liche.cn/meijiaka-zy/materials/a5e4120cbf4a401c88aee857b92b156d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'eb1d5a55a60041cc9bf447f1a7eb998d', 'https://media.liche.cn/meijiaka-zy/materials/eb1d5a55a60041cc9bf447f1a7eb998d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'd5f73ee06a364aa1b73acd1d95d688cd', 'https://media.liche.cn/meijiaka-zy/materials/d5f73ee06a364aa1b73acd1d95d688cd.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), '3a00729cfb82485fb5175ad69be298fb', 'https://media.liche.cn/meijiaka-zy/materials/3a00729cfb82485fb5175ad69be298fb.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '投影仪要买贵的' AND level = 3), 'f22dc47ddfb74e4385e23a7dd4c6c750', 'https://media.liche.cn/meijiaka-zy/materials/f22dc47ddfb74e4385e23a7dd4c6c750.mp4', 5.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'bffa5e9e969d4eed8de66bbe91cf4070', 'https://media.liche.cn/meijiaka-zy/materials/bffa5e9e969d4eed8de66bbe91cf4070.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '3cba87d2d7de43abb5a0b176b4390a2e', 'https://media.liche.cn/meijiaka-zy/materials/3cba87d2d7de43abb5a0b176b4390a2e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'fb56951585af4d22afc0288a93fa0faa', 'https://media.liche.cn/meijiaka-zy/materials/fb56951585af4d22afc0288a93fa0faa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'f60cb204862b451ba04bdeb541d626aa', 'https://media.liche.cn/meijiaka-zy/materials/f60cb204862b451ba04bdeb541d626aa.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'f7068cfcded546fe8829c5b32bf1387e', 'https://media.liche.cn/meijiaka-zy/materials/f7068cfcded546fe8829c5b32bf1387e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'ce7d8a7605b04a15bb2cade2796300ef', 'https://media.liche.cn/meijiaka-zy/materials/ce7d8a7605b04a15bb2cade2796300ef.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '04b016f34fae404b9c9e256e696f2d5f', 'https://media.liche.cn/meijiaka-zy/materials/04b016f34fae404b9c9e256e696f2d5f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '55dcc9ee840b4bb29ea641bca8648154', 'https://media.liche.cn/meijiaka-zy/materials/55dcc9ee840b4bb29ea641bca8648154.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '5789519ed2124f41be9d129eddd9b886', 'https://media.liche.cn/meijiaka-zy/materials/5789519ed2124f41be9d129eddd9b886.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '7105b1baf55c42f9a696c10650d7e75b', 'https://media.liche.cn/meijiaka-zy/materials/7105b1baf55c42f9a696c10650d7e75b.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), '1875c47e29a94528960afeaf39723d03', 'https://media.liche.cn/meijiaka-zy/materials/1875c47e29a94528960afeaf39723d03.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '4b2499109b264074bb54930771c86c5b', 'https://media.liche.cn/meijiaka-zy/materials/4b2499109b264074bb54930771c86c5b.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '滑轨要买贵的' AND level = 3), 'de5a46df3d894e38874fc58094f56b43', 'https://media.liche.cn/meijiaka-zy/materials/de5a46df3d894e38874fc58094f56b43.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '988c9f941097423e8ca269024e386655', 'https://media.liche.cn/meijiaka-zy/materials/988c9f941097423e8ca269024e386655.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'dd4bd63338cb47038ec60024d81d4ecd', 'https://media.liche.cn/meijiaka-zy/materials/dd4bd63338cb47038ec60024d81d4ecd.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '243dd32412584df68eac53aa863250fb', 'https://media.liche.cn/meijiaka-zy/materials/243dd32412584df68eac53aa863250fb.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '71dea62b980040a7b0ce09f2fda63fc2', 'https://media.liche.cn/meijiaka-zy/materials/71dea62b980040a7b0ce09f2fda63fc2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'f641c2ffa4a9400a9886b850f83e5ba2', 'https://media.liche.cn/meijiaka-zy/materials/f641c2ffa4a9400a9886b850f83e5ba2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '1a6734f004744881a5c8db1414645de7', 'https://media.liche.cn/meijiaka-zy/materials/1a6734f004744881a5c8db1414645de7.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '534ec03d35054e328cf0c483f273488d', 'https://media.liche.cn/meijiaka-zy/materials/534ec03d35054e328cf0c483f273488d.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '915236f9aa8d4f9aa6d735674d42e75b', 'https://media.liche.cn/meijiaka-zy/materials/915236f9aa8d4f9aa6d735674d42e75b.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '0e275b7a5ee447b194bc0d9863e117e6', 'https://media.liche.cn/meijiaka-zy/materials/0e275b7a5ee447b194bc0d9863e117e6.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'c17e80e684b24fdf96204e39ade1961a', 'https://media.liche.cn/meijiaka-zy/materials/c17e80e684b24fdf96204e39ade1961a.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'a30dd8d5868e494baa60addae81edfd2', 'https://media.liche.cn/meijiaka-zy/materials/a30dd8d5868e494baa60addae81edfd2.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '006c573dc8f24f27b5655d5d38347ebc', 'https://media.liche.cn/meijiaka-zy/materials/006c573dc8f24f27b5655d5d38347ebc.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '2baa15500def460eb875b3944345a9b2', 'https://media.liche.cn/meijiaka-zy/materials/2baa15500def460eb875b3944345a9b2.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '72cb24f3ecc3485d8cb72a00d23d08a0', 'https://media.liche.cn/meijiaka-zy/materials/72cb24f3ecc3485d8cb72a00d23d08a0.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'bb2e1316b9a04ddbabf18a292f5fcd7b', 'https://media.liche.cn/meijiaka-zy/materials/bb2e1316b9a04ddbabf18a292f5fcd7b.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'be35e424251342008eead2c700670320', 'https://media.liche.cn/meijiaka-zy/materials/be35e424251342008eead2c700670320.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '0f8243e3362042a09893246abe84b59c', 'https://media.liche.cn/meijiaka-zy/materials/0f8243e3362042a09893246abe84b59c.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '064282f793e143adae3cf31b272f62fd', 'https://media.liche.cn/meijiaka-zy/materials/064282f793e143adae3cf31b272f62fd.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '933aa40c667a4144a910e0893eed3639', 'https://media.liche.cn/meijiaka-zy/materials/933aa40c667a4144a910e0893eed3639.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '47a367859f8847fab9dc8c6aab5c6950', 'https://media.liche.cn/meijiaka-zy/materials/47a367859f8847fab9dc8c6aab5c6950.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'c80b0d7f0e0d459990909891f83401b3', 'https://media.liche.cn/meijiaka-zy/materials/c80b0d7f0e0d459990909891f83401b3.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '2b46e5473861488aa07c3065419f413f', 'https://media.liche.cn/meijiaka-zy/materials/2b46e5473861488aa07c3065419f413f.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '913fd8f6c2eb42d6868b0797f9a22454', 'https://media.liche.cn/meijiaka-zy/materials/913fd8f6c2eb42d6868b0797f9a22454.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'cac0f095b63a406eaefd60ed8a106315', 'https://media.liche.cn/meijiaka-zy/materials/cac0f095b63a406eaefd60ed8a106315.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'c9b4efb0b0334f86baad10f1cbda8b3a', 'https://media.liche.cn/meijiaka-zy/materials/c9b4efb0b0334f86baad10f1cbda8b3a.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'c5f1f7d996ec4763aea3ab6edd07eb06', 'https://media.liche.cn/meijiaka-zy/materials/c5f1f7d996ec4763aea3ab6edd07eb06.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '6f7b7c5264444fb59c61c496e76c88ee', 'https://media.liche.cn/meijiaka-zy/materials/6f7b7c5264444fb59c61c496e76c88ee.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '3567eb72e78d4156824974ec090cda5e', 'https://media.liche.cn/meijiaka-zy/materials/3567eb72e78d4156824974ec090cda5e.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '6b6d3453e63740b39808be7cf0745865', 'https://media.liche.cn/meijiaka-zy/materials/6b6d3453e63740b39808be7cf0745865.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '516fde92bc804d2dac7e8fd141308f9e', 'https://media.liche.cn/meijiaka-zy/materials/516fde92bc804d2dac7e8fd141308f9e.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'd858d16db11b491eb71805983fe73018', 'https://media.liche.cn/meijiaka-zy/materials/d858d16db11b491eb71805983fe73018.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'ab6a9d90de824bbca218a8b4f5e76a59', 'https://media.liche.cn/meijiaka-zy/materials/ab6a9d90de824bbca218a8b4f5e76a59.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'c9f4a33f158246c3aa6f09aeefbca163', 'https://media.liche.cn/meijiaka-zy/materials/c9f4a33f158246c3aa6f09aeefbca163.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '4aa12a306f5f47318d0b0c845812a06d', 'https://media.liche.cn/meijiaka-zy/materials/4aa12a306f5f47318d0b0c845812a06d.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'b9cc562788294b6289a9ec2f70ff513f', 'https://media.liche.cn/meijiaka-zy/materials/b9cc562788294b6289a9ec2f70ff513f.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'e1cc84567e9b41a0b7da16de6243b62f', 'https://media.liche.cn/meijiaka-zy/materials/e1cc84567e9b41a0b7da16de6243b62f.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), 'ef50596a1671435385bc5872eac75bf8', 'https://media.liche.cn/meijiaka-zy/materials/ef50596a1671435385bc5872eac75bf8.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '6c1216dd7f56481f96f7969dbf111237', 'https://media.liche.cn/meijiaka-zy/materials/6c1216dd7f56481f96f7969dbf111237.mp4', 3.04, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '灯具不要买贵的' AND level = 3), '3e667e1f588a4709a90d6f28d0cab032', 'https://media.liche.cn/meijiaka-zy/materials/3e667e1f588a4709a90d6f28d0cab032.mp4', 3.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), '41136ba9352148d785424537a4560b8a', 'https://media.liche.cn/meijiaka-zy/materials/41136ba9352148d785424537a4560b8a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), 'ce2e1e6295de4b5196afc8d909c4bf84', 'https://media.liche.cn/meijiaka-zy/materials/ce2e1e6295de4b5196afc8d909c4bf84.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), '736a5334423445b4b8d23c8d519b3e66', 'https://media.liche.cn/meijiaka-zy/materials/736a5334423445b4b8d23c8d519b3e66.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '37664294d36d470abdd2933ce2e143a3', 'https://media.liche.cn/meijiaka-zy/materials/37664294d36d470abdd2933ce2e143a3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), '897b66dcf9e94158b453a8f4d6677160', 'https://media.liche.cn/meijiaka-zy/materials/897b66dcf9e94158b453a8f4d6677160.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), 'd165f3d1aaad4926a2e906efd631e6ab', 'https://media.liche.cn/meijiaka-zy/materials/d165f3d1aaad4926a2e906efd631e6ab.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), 'd48c166cda534262ba2afa1d1f53e6db', 'https://media.liche.cn/meijiaka-zy/materials/d48c166cda534262ba2afa1d1f53e6db.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), '9dcbccffda114587ace5aea8a8bfd594', 'https://media.liche.cn/meijiaka-zy/materials/9dcbccffda114587ace5aea8a8bfd594.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '53892049b3bd4434bca56abb24184a18', 'https://media.liche.cn/meijiaka-zy/materials/53892049b3bd4434bca56abb24184a18.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '530d1c9c3a964c82bfdf456c825d7e3d', 'https://media.liche.cn/meijiaka-zy/materials/530d1c9c3a964c82bfdf456c825d7e3d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'f5e85b5bfb7a4195ae3d412e1b4a2ac2', 'https://media.liche.cn/meijiaka-zy/materials/f5e85b5bfb7a4195ae3d412e1b4a2ac2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'ed645a0d631b4e6396060c719d54e9ba', 'https://media.liche.cn/meijiaka-zy/materials/ed645a0d631b4e6396060c719d54e9ba.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'fe153e33b4344025b8408cb3b0bd8e33', 'https://media.liche.cn/meijiaka-zy/materials/fe153e33b4344025b8408cb3b0bd8e33.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), 'd7dc46067e344cf0a07687bb14bb792f', 'https://media.liche.cn/meijiaka-zy/materials/d7dc46067e344cf0a07687bb14bb792f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), '49a18b231fdd413b9588b8fb62a95316', 'https://media.liche.cn/meijiaka-zy/materials/49a18b231fdd413b9588b8fb62a95316.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂吊灯' AND level = 3), 'c717421efbe3425faab84389f759892b', 'https://media.liche.cn/meijiaka-zy/materials/c717421efbe3425faab84389f759892b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '63ea40a6bb7c455989a65b0b23b9ba7f', 'https://media.liche.cn/meijiaka-zy/materials/63ea40a6bb7c455989a65b0b23b9ba7f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'bdbbb6577ce94cc0b283164b97606335', 'https://media.liche.cn/meijiaka-zy/materials/bdbbb6577ce94cc0b283164b97606335.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '682cdd1a71044e10ba493c02c6d53bf0', 'https://media.liche.cn/meijiaka-zy/materials/682cdd1a71044e10ba493c02c6d53bf0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '2ec008c738da48b9b8b44193d339f046', 'https://media.liche.cn/meijiaka-zy/materials/2ec008c738da48b9b8b44193d339f046.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '162431218da7406fb3fc68ebacdb6d7e', 'https://media.liche.cn/meijiaka-zy/materials/162431218da7406fb3fc68ebacdb6d7e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '2a09162259cc4217b5bb4cd58dd536cb', 'https://media.liche.cn/meijiaka-zy/materials/2a09162259cc4217b5bb4cd58dd536cb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '67676eb5e62449cfa28a87675a152989', 'https://media.liche.cn/meijiaka-zy/materials/67676eb5e62449cfa28a87675a152989.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'fa759e4c2c60438abac8550ab32c3dea', 'https://media.liche.cn/meijiaka-zy/materials/fa759e4c2c60438abac8550ab32c3dea.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'a9d7a5781aa34fedb1f734e91dc4ffbb', 'https://media.liche.cn/meijiaka-zy/materials/a9d7a5781aa34fedb1f734e91dc4ffbb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '3189842096714eefaa448b4e5bb99e2d', 'https://media.liche.cn/meijiaka-zy/materials/3189842096714eefaa448b4e5bb99e2d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'c65bd1beb9c7425694b551e1ce47b0a5', 'https://media.liche.cn/meijiaka-zy/materials/c65bd1beb9c7425694b551e1ce47b0a5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), 'dc36d9cad12f4ce6aaa68857963b1e46', 'https://media.liche.cn/meijiaka-zy/materials/dc36d9cad12f4ce6aaa68857963b1e46.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '6318af9bab3b4586ae0b8151973f4651', 'https://media.liche.cn/meijiaka-zy/materials/6318af9bab3b4586ae0b8151973f4651.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮' AND level = 3), '37c74d3c4dbc47e8a335a29acb186132', 'https://media.liche.cn/meijiaka-zy/materials/37c74d3c4dbc47e8a335a29acb186132.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '363cdea37eee48d78c8cb81d48604b3b', 'https://media.liche.cn/meijiaka-zy/materials/363cdea37eee48d78c8cb81d48604b3b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '214a6621634b4b5fb34427d4bac4e8fb', 'https://media.liche.cn/meijiaka-zy/materials/214a6621634b4b5fb34427d4bac4e8fb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), 'db5ea70fd51d49a4b43e157e7b219774', 'https://media.liche.cn/meijiaka-zy/materials/db5ea70fd51d49a4b43e157e7b219774.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), '614add3140fc46c88eb9c39027f53ac8', 'https://media.liche.cn/meijiaka-zy/materials/614add3140fc46c88eb9c39027f53ac8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), '911f7671ee0b4152b3fe4dfa708e9920', 'https://media.liche.cn/meijiaka-zy/materials/911f7671ee0b4152b3fe4dfa708e9920.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), 'df6b1f6f9a62469aaa220e449741e5cc', 'https://media.liche.cn/meijiaka-zy/materials/df6b1f6f9a62469aaa220e449741e5cc.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), '474504f7c03645bd89df221954a278e2', 'https://media.liche.cn/meijiaka-zy/materials/474504f7c03645bd89df221954a278e2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), '962595f5c4a743aca22cb1f947568cbc', 'https://media.liche.cn/meijiaka-zy/materials/962595f5c4a743aca22cb1f947568cbc.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '697ec4f08b8149f1a293bf57656752ee', 'https://media.liche.cn/meijiaka-zy/materials/697ec4f08b8149f1a293bf57656752ee.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要分体灶' AND level = 3), 'be1930d261784928a36327a8dc3bfa84', 'https://media.liche.cn/meijiaka-zy/materials/be1930d261784928a36327a8dc3bfa84.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), 'a6c711d4d8494386b09ebde3e295169f', 'https://media.liche.cn/meijiaka-zy/materials/a6c711d4d8494386b09ebde3e295169f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '295ec4723d1c4559923219249c268411', 'https://media.liche.cn/meijiaka-zy/materials/295ec4723d1c4559923219249c268411.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '8f73547a870b475b9c7efdb0b7166ad9', 'https://media.liche.cn/meijiaka-zy/materials/8f73547a870b475b9c7efdb0b7166ad9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '25ec38716a1047e5bcfbf7f9c6ace8fb', 'https://media.liche.cn/meijiaka-zy/materials/25ec38716a1047e5bcfbf7f9c6ace8fb.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '6cd2bcfa4f674b92923a3f4978b51c95', 'https://media.liche.cn/meijiaka-zy/materials/6cd2bcfa4f674b92923a3f4978b51c95.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '5fed0ff95e874dca95f49b97aed35361', 'https://media.liche.cn/meijiaka-zy/materials/5fed0ff95e874dca95f49b97aed35361.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '9d0268e013e34f078f89b71ae399756c', 'https://media.liche.cn/meijiaka-zy/materials/9d0268e013e34f078f89b71ae399756c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), 'a2f45e42ecbe4d41be1965f936592b78', 'https://media.liche.cn/meijiaka-zy/materials/a2f45e42ecbe4d41be1965f936592b78.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '68b6293963434dba99acdb18232bcca1', 'https://media.liche.cn/meijiaka-zy/materials/68b6293963434dba99acdb18232bcca1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '478f7bd4130b48c2bb1e7827a72f1c6c', 'https://media.liche.cn/meijiaka-zy/materials/478f7bd4130b48c2bb1e7827a72f1c6c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '522e73407ef84ca08b6cbf1bf92bd5e1', 'https://media.liche.cn/meijiaka-zy/materials/522e73407ef84ca08b6cbf1bf92bd5e1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), 'f2aad662ad6e446ab33a9cc169fbf078', 'https://media.liche.cn/meijiaka-zy/materials/f2aad662ad6e446ab33a9cc169fbf078.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要隐藏式插座' AND level = 3), '6d8ddd4158ec474281d78af5ffcde0c5', 'https://media.liche.cn/meijiaka-zy/materials/6d8ddd4158ec474281d78af5ffcde0c5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), 'c857ac7cffc442aca8527e4a71b5e725', 'https://media.liche.cn/meijiaka-zy/materials/c857ac7cffc442aca8527e4a71b5e725.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), 'd3c740fb5fa54ce2b41eb23e17d7e1ae', 'https://media.liche.cn/meijiaka-zy/materials/d3c740fb5fa54ce2b41eb23e17d7e1ae.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '6f5174788f8c44ae9baa0298d74f1d1d', 'https://media.liche.cn/meijiaka-zy/materials/6f5174788f8c44ae9baa0298d74f1d1d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '4aaa05319f8e4b558fae7c451254723e', 'https://media.liche.cn/meijiaka-zy/materials/4aaa05319f8e4b558fae7c451254723e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '0bdd57d7556b4b33838ac6dd68a62e7b', 'https://media.liche.cn/meijiaka-zy/materials/0bdd57d7556b4b33838ac6dd68a62e7b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), 'be5b984494a34654aa46a48d5f2fc9f9', 'https://media.liche.cn/meijiaka-zy/materials/be5b984494a34654aa46a48d5f2fc9f9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '2e2a0c76bf56432ca503dc43b898404d', 'https://media.liche.cn/meijiaka-zy/materials/2e2a0c76bf56432ca503dc43b898404d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), 'd3d2a04bc2ce4b87b452e378331a9de1', 'https://media.liche.cn/meijiaka-zy/materials/d3d2a04bc2ce4b87b452e378331a9de1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), 'e1050a1052fd4752bddb2722681c3167', 'https://media.liche.cn/meijiaka-zy/materials/e1050a1052fd4752bddb2722681c3167.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要开放式收纳柜' AND level = 3), '0fc851064bdd49c3b9cfd03b6bda60c7', 'https://media.liche.cn/meijiaka-zy/materials/0fc851064bdd49c3b9cfd03b6bda60c7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要射灯' AND level = 3), '0cfb7964e5374032982cf2b6092d4007', 'https://media.liche.cn/meijiaka-zy/materials/0cfb7964e5374032982cf2b6092d4007.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要射灯' AND level = 3), '78ba85edebae4a37a183c53660b18985', 'https://media.liche.cn/meijiaka-zy/materials/78ba85edebae4a37a183c53660b18985.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要射灯' AND level = 3), '549c7dc2cb8e4dfba269ba2e70065fe6', 'https://media.liche.cn/meijiaka-zy/materials/549c7dc2cb8e4dfba269ba2e70065fe6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要射灯' AND level = 3), '11e1336415c5416083508c5852ec046f', 'https://media.liche.cn/meijiaka-zy/materials/11e1336415c5416083508c5852ec046f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '4f61a7dd0fef4a16bc2a25a2d0e8ea18', 'https://media.liche.cn/meijiaka-zy/materials/4f61a7dd0fef4a16bc2a25a2d0e8ea18.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), 'b2c57b6143274316a3f31fd78b749149', 'https://media.liche.cn/meijiaka-zy/materials/b2c57b6143274316a3f31fd78b749149.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '6c82e5fb5a0f484cb46b64ca446faa78', 'https://media.liche.cn/meijiaka-zy/materials/6c82e5fb5a0f484cb46b64ca446faa78.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要射灯' AND level = 3), '386e283bb01540b58393f390db3d7761', 'https://media.liche.cn/meijiaka-zy/materials/386e283bb01540b58393f390db3d7761.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '748478f56970418f8f08a3884709285a', 'https://media.liche.cn/meijiaka-zy/materials/748478f56970418f8f08a3884709285a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '26e143be6b37453589bf920cf42a0b61', 'https://media.liche.cn/meijiaka-zy/materials/26e143be6b37453589bf920cf42a0b61.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '13d07a2f305740bea4a573933e512db8', 'https://media.liche.cn/meijiaka-zy/materials/13d07a2f305740bea4a573933e512db8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '8d64ee8a80ab4258a42d1a6ca81f740c', 'https://media.liche.cn/meijiaka-zy/materials/8d64ee8a80ab4258a42d1a6ca81f740c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '567fa4d5c8ee4896a89ad8fd62983b68', 'https://media.liche.cn/meijiaka-zy/materials/567fa4d5c8ee4896a89ad8fd62983b68.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通衣架' AND level = 3), '4f351eb483e3452b9b0a02773f8c293a', 'https://media.liche.cn/meijiaka-zy/materials/4f351eb483e3452b9b0a02773f8c293a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '8d351ce2cad741408b63a5ae00dd403f', 'https://media.liche.cn/meijiaka-zy/materials/8d351ce2cad741408b63a5ae00dd403f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '913bbb24713e472ba8f47ad57f1845f0', 'https://media.liche.cn/meijiaka-zy/materials/913bbb24713e472ba8f47ad57f1845f0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), '3bc2d4f10c434b7e91ac710d639b24a9', 'https://media.liche.cn/meijiaka-zy/materials/3bc2d4f10c434b7e91ac710d639b24a9.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'bd031cb0bbbf4411a3571ab751ad338e', 'https://media.liche.cn/meijiaka-zy/materials/bd031cb0bbbf4411a3571ab751ad338e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), '2f1ed10afad049be8d5cf7d042fad900', 'https://media.liche.cn/meijiaka-zy/materials/2f1ed10afad049be8d5cf7d042fad900.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '8d8b83241faf463996d87a42358c623c', 'https://media.liche.cn/meijiaka-zy/materials/8d8b83241faf463996d87a42358c623c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), 'bf3ef26d75034de3b535d391f427d2c8', 'https://media.liche.cn/meijiaka-zy/materials/bf3ef26d75034de3b535d391f427d2c8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), 'd820b94ef7e14d809668277b16e06c6c', 'https://media.liche.cn/meijiaka-zy/materials/d820b94ef7e14d809668277b16e06c6c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'c9fbbd9bd5ad40e29811756b25244111', 'https://media.liche.cn/meijiaka-zy/materials/c9fbbd9bd5ad40e29811756b25244111.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), 'b0bb98c0ea11486ba997695480be61bd', 'https://media.liche.cn/meijiaka-zy/materials/b0bb98c0ea11486ba997695480be61bd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'cc15716e15ae4a69b59172a8f0c1e6b0', 'https://media.liche.cn/meijiaka-zy/materials/cc15716e15ae4a69b59172a8f0c1e6b0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '49f4765f1fb54358865f8f3274166dd2', 'https://media.liche.cn/meijiaka-zy/materials/49f4765f1fb54358865f8f3274166dd2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '010fcb74d81a477ea8eff9afba1dd9fd', 'https://media.liche.cn/meijiaka-zy/materials/010fcb74d81a477ea8eff9afba1dd9fd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'efa23eeb6be04e6a9ce19fd2b6371e82', 'https://media.liche.cn/meijiaka-zy/materials/efa23eeb6be04e6a9ce19fd2b6371e82.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'c2fcc2e9faa345f4bfba1ed8c083660e', 'https://media.liche.cn/meijiaka-zy/materials/c2fcc2e9faa345f4bfba1ed8c083660e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), '83a8491db33944ffbe24575b1a648b1a', 'https://media.liche.cn/meijiaka-zy/materials/83a8491db33944ffbe24575b1a648b1a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'aad37f5e81c74a809bfc97fdc837cb3b', 'https://media.liche.cn/meijiaka-zy/materials/aad37f5e81c74a809bfc97fdc837cb3b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要回型吊顶' AND level = 3), 'ca8daaf6b0c74684b81aca907e3ab514', 'https://media.liche.cn/meijiaka-zy/materials/ca8daaf6b0c74684b81aca907e3ab514.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'b478bf4af23841958de38efc10273c8b', 'https://media.liche.cn/meijiaka-zy/materials/b478bf4af23841958de38efc10273c8b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要乳胶漆' AND level = 3), '51db305228d945709673f7861cae4332', 'https://media.liche.cn/meijiaka-zy/materials/51db305228d945709673f7861cae4332.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'd2b2ae5f375c442bb75719ece42c7cb8', 'https://media.liche.cn/meijiaka-zy/materials/d2b2ae5f375c442bb75719ece42c7cb8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '2acdd2e9fb934369b63d630a48feab3a', 'https://media.liche.cn/meijiaka-zy/materials/2acdd2e9fb934369b63d630a48feab3a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '46770644d73d41e4b229145d001ced96', 'https://media.liche.cn/meijiaka-zy/materials/46770644d73d41e4b229145d001ced96.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '1683a4d89a5b41eb963ecf2615e763c8', 'https://media.liche.cn/meijiaka-zy/materials/1683a4d89a5b41eb963ecf2615e763c8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'cf08b5c0c7364fe1924b24ff22a50ea6', 'https://media.liche.cn/meijiaka-zy/materials/cf08b5c0c7364fe1924b24ff22a50ea6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'e2855e6cca05482b8a2a29cfcf8e437d', 'https://media.liche.cn/meijiaka-zy/materials/e2855e6cca05482b8a2a29cfcf8e437d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '0b746d78fe80493ba6d0f063a147c52e', 'https://media.liche.cn/meijiaka-zy/materials/0b746d78fe80493ba6d0f063a147c52e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'c87d60e88bb549b0a50687c6cda368cc', 'https://media.liche.cn/meijiaka-zy/materials/c87d60e88bb549b0a50687c6cda368cc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'dc3ca4df844b4ae8b67c8007f25ff550', 'https://media.liche.cn/meijiaka-zy/materials/dc3ca4df844b4ae8b67c8007f25ff550.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '23200188d6324eea9fbe742f8ac19983', 'https://media.liche.cn/meijiaka-zy/materials/23200188d6324eea9fbe742f8ac19983.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '2b7ed52582f94d519fd2e0cc8bf1c75e', 'https://media.liche.cn/meijiaka-zy/materials/2b7ed52582f94d519fd2e0cc8bf1c75e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '5e94c908a99c4f8c9dee26f8fc0104ea', 'https://media.liche.cn/meijiaka-zy/materials/5e94c908a99c4f8c9dee26f8fc0104ea.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'cd7d1033012a42048206ffca3e94a587', 'https://media.liche.cn/meijiaka-zy/materials/cd7d1033012a42048206ffca3e94a587.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '2d7f0faa69c74191a6c6d079dca43820', 'https://media.liche.cn/meijiaka-zy/materials/2d7f0faa69c74191a6c6d079dca43820.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), '61f099c17ce34ed59846c42c5886f252', 'https://media.liche.cn/meijiaka-zy/materials/61f099c17ce34ed59846c42c5886f252.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要肤感衣柜门' AND level = 3), 'b344e99b4abb4c76878a4123e27d04b3', 'https://media.liche.cn/meijiaka-zy/materials/b344e99b4abb4c76878a4123e27d04b3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '8be2dd9d185243e79d1fe97129b556ae', 'https://media.liche.cn/meijiaka-zy/materials/8be2dd9d185243e79d1fe97129b556ae.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '9a8f372e09ab449eb6160fc443a421c8', 'https://media.liche.cn/meijiaka-zy/materials/9a8f372e09ab449eb6160fc443a421c8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '810e1871a9804df6b5328e05f3db264e', 'https://media.liche.cn/meijiaka-zy/materials/810e1871a9804df6b5328e05f3db264e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '56ad4d103cd347578807aeb9e90c93bd', 'https://media.liche.cn/meijiaka-zy/materials/56ad4d103cd347578807aeb9e90c93bd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), 'f3d1e749029f46388d441c21f196dd09', 'https://media.liche.cn/meijiaka-zy/materials/f3d1e749029f46388d441c21f196dd09.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '37ffb710e66a4a2ca85d5dccf374215e', 'https://media.liche.cn/meijiaka-zy/materials/37ffb710e66a4a2ca85d5dccf374215e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), 'd21c248fe351430a964da57665b4e2b7', 'https://media.liche.cn/meijiaka-zy/materials/d21c248fe351430a964da57665b4e2b7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), 'de4d47925e774a74974cf5230a848a77', 'https://media.liche.cn/meijiaka-zy/materials/de4d47925e774a74974cf5230a848a77.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), '19028a0b4ab749f6a184c911be13f37a', 'https://media.liche.cn/meijiaka-zy/materials/19028a0b4ab749f6a184c911be13f37a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), 'cb7c8e792c8d4ceca2f0fcbfa08e06bb', 'https://media.liche.cn/meijiaka-zy/materials/cb7c8e792c8d4ceca2f0fcbfa08e06bb.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), '66a506f443aa436f8f81a5465df3345e', 'https://media.liche.cn/meijiaka-zy/materials/66a506f443aa436f8f81a5465df3345e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), 'd638c266fe60404aa515a5810b8bf825', 'https://media.liche.cn/meijiaka-zy/materials/d638c266fe60404aa515a5810b8bf825.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '63f5e38e7dd341d29d92eca335dc9849', 'https://media.liche.cn/meijiaka-zy/materials/63f5e38e7dd341d29d92eca335dc9849.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), '2bddd09a2a59493bb0a68ae0c3db9a3c', 'https://media.liche.cn/meijiaka-zy/materials/2bddd09a2a59493bb0a68ae0c3db9a3c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要吸顶灯' AND level = 3), '337507e727794693ac24a6311d6981da', 'https://media.liche.cn/meijiaka-zy/materials/337507e727794693ac24a6311d6981da.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), 'b7a3ca78169c44afb6b1640edcefa244', 'https://media.liche.cn/meijiaka-zy/materials/b7a3ca78169c44afb6b1640edcefa244.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), 'e129a6182784413b88e4ff31233f07c8', 'https://media.liche.cn/meijiaka-zy/materials/e129a6182784413b88e4ff31233f07c8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬空马桶' AND level = 3), '22a8aa82931346cca2f8c25a5d06eaa2', 'https://media.liche.cn/meijiaka-zy/materials/22a8aa82931346cca2f8c25a5d06eaa2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬空马桶' AND level = 3), 'a4ecfbb8e1594179bf8582d014a0931a', 'https://media.liche.cn/meijiaka-zy/materials/a4ecfbb8e1594179bf8582d014a0931a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬空马桶' AND level = 3), 'b5f72438490a470dbd14a283e25e79ec', 'https://media.liche.cn/meijiaka-zy/materials/b5f72438490a470dbd14a283e25e79ec.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要一体门' AND level = 3), '6bbe085f77f54e5783cc563569ea6230', 'https://media.liche.cn/meijiaka-zy/materials/6bbe085f77f54e5783cc563569ea6230.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬空马桶' AND level = 3), '0f4471f66fd54ec0a4376b9d95ab6d3a', 'https://media.liche.cn/meijiaka-zy/materials/0f4471f66fd54ec0a4376b9d95ab6d3a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬空马桶' AND level = 3), '7d4c3b837f8d4f5ab14af98a71d8516d', 'https://media.liche.cn/meijiaka-zy/materials/7d4c3b837f8d4f5ab14af98a71d8516d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), '3edf39bd052c4a05b4921edd44ec0d9c', 'https://media.liche.cn/meijiaka-zy/materials/3edf39bd052c4a05b4921edd44ec0d9c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), '8108fdd76563419c84ac082ee4057584', 'https://media.liche.cn/meijiaka-zy/materials/8108fdd76563419c84ac082ee4057584.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), '203873929e2c40db90582e93e22de3a0', 'https://media.liche.cn/meijiaka-zy/materials/203873929e2c40db90582e93e22de3a0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), '94667de868ff459584dddbd0e9353da8', 'https://media.liche.cn/meijiaka-zy/materials/94667de868ff459584dddbd0e9353da8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), 'b264e5792269486ca3ecfe305cfc3ada', 'https://media.liche.cn/meijiaka-zy/materials/b264e5792269486ca3ecfe305cfc3ada.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), '9c1c029333c8400dad2a7008aea2ca23', 'https://media.liche.cn/meijiaka-zy/materials/9c1c029333c8400dad2a7008aea2ca23.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要过门石' AND level = 3), '88cfb5ae625a4917820488c5a5c1bb6f', 'https://media.liche.cn/meijiaka-zy/materials/88cfb5ae625a4917820488c5a5c1bb6f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), '2916f953fba4459cb6939879f79eb817', 'https://media.liche.cn/meijiaka-zy/materials/2916f953fba4459cb6939879f79eb817.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '3ad42b8314ee4414868e2f3ce4c5e2b9', 'https://media.liche.cn/meijiaka-zy/materials/3ad42b8314ee4414868e2f3ce4c5e2b9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'e5bf8adefe4e4085bea7fe00e306019a', 'https://media.liche.cn/meijiaka-zy/materials/e5bf8adefe4e4085bea7fe00e306019a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '3b3892c328c74aa28815791093249c35', 'https://media.liche.cn/meijiaka-zy/materials/3b3892c328c74aa28815791093249c35.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '77eddda820274a08820f3d692219d5b1', 'https://media.liche.cn/meijiaka-zy/materials/77eddda820274a08820f3d692219d5b1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '4b11052dbd9145df85adddd5c9ca453a', 'https://media.liche.cn/meijiaka-zy/materials/4b11052dbd9145df85adddd5c9ca453a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '61b2c21bce3e4e3e9fec381e529e78f2', 'https://media.liche.cn/meijiaka-zy/materials/61b2c21bce3e4e3e9fec381e529e78f2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '63cf75e368884cdd8b47926c136abaa5', 'https://media.liche.cn/meijiaka-zy/materials/63cf75e368884cdd8b47926c136abaa5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '5f1e6e97e67c4a1e849899efcf46401e', 'https://media.liche.cn/meijiaka-zy/materials/5f1e6e97e67c4a1e849899efcf46401e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), '1e7b5f3b56154062a56f2eea3a676591', 'https://media.liche.cn/meijiaka-zy/materials/1e7b5f3b56154062a56f2eea3a676591.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), 'ae65578d934344e99b1f02aaa00d42c7', 'https://media.liche.cn/meijiaka-zy/materials/ae65578d934344e99b1f02aaa00d42c7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), '3b547526027b407a9c7fbabe128e1aeb', 'https://media.liche.cn/meijiaka-zy/materials/3b547526027b407a9c7fbabe128e1aeb.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要榻榻米' AND level = 3), 'e21794b8ff2f4dc69a72f10b695c64b4', 'https://media.liche.cn/meijiaka-zy/materials/e21794b8ff2f4dc69a72f10b695c64b4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '33556fcaf489438489549f6f50331eca', 'https://media.liche.cn/meijiaka-zy/materials/33556fcaf489438489549f6f50331eca.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '917ec76d48bb4ba3a71192b6c825427d', 'https://media.liche.cn/meijiaka-zy/materials/917ec76d48bb4ba3a71192b6c825427d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '95ecdfd0a3c6461089e4d31e823e9ad9', 'https://media.liche.cn/meijiaka-zy/materials/95ecdfd0a3c6461089e4d31e823e9ad9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '9a9f036b5bdc4e4fa21012a210e700b7', 'https://media.liche.cn/meijiaka-zy/materials/9a9f036b5bdc4e4fa21012a210e700b7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'cf58e158c7ba49069d5c4e16395b2072', 'https://media.liche.cn/meijiaka-zy/materials/cf58e158c7ba49069d5c4e16395b2072.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'c064d5f427e440aab012c8c1812ada6c', 'https://media.liche.cn/meijiaka-zy/materials/c064d5f427e440aab012c8c1812ada6c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'ab3047885aa64389be0c243f4d8a2415', 'https://media.liche.cn/meijiaka-zy/materials/ab3047885aa64389be0c243f4d8a2415.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'c36b038b091b44539e67a73d449a62c4', 'https://media.liche.cn/meijiaka-zy/materials/c36b038b091b44539e67a73d449a62c4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '118276fbf27a4436b3c550419b238613', 'https://media.liche.cn/meijiaka-zy/materials/118276fbf27a4436b3c550419b238613.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'a26146bbfbfb4dbdade94b25d0082ed1', 'https://media.liche.cn/meijiaka-zy/materials/a26146bbfbfb4dbdade94b25d0082ed1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), 'a970ba429d614c2da5effc4b2a222008', 'https://media.liche.cn/meijiaka-zy/materials/a970ba429d614c2da5effc4b2a222008.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要双眼皮吊顶' AND level = 3), '11ccd36026be45e78d9abb212042fe5d', 'https://media.liche.cn/meijiaka-zy/materials/11ccd36026be45e78d9abb212042fe5d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要简约背景墙' AND level = 3), '423cab9371f14bc7a27659830a461c36', 'https://media.liche.cn/meijiaka-zy/materials/423cab9371f14bc7a27659830a461c36.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要简约背景墙' AND level = 3), '8d1f60f04dd744ea997277de82806240', 'https://media.liche.cn/meijiaka-zy/materials/8d1f60f04dd744ea997277de82806240.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要反弹器' AND level = 3), '68c4adb9d22d4e759b0d7c34ffbe9aa0', 'https://media.liche.cn/meijiaka-zy/materials/68c4adb9d22d4e759b0d7c34ffbe9aa0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要简约背景墙' AND level = 3), 'a525b0b916f846928bb96c882e0a2f6d', 'https://media.liche.cn/meijiaka-zy/materials/a525b0b916f846928bb96c882e0a2f6d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要反弹器' AND level = 3), '1576c585d0c74fd48678a818346ea47c', 'https://media.liche.cn/meijiaka-zy/materials/1576c585d0c74fd48678a818346ea47c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要简约背景墙' AND level = 3), '18299f5241fa48599dadd2c23f8d1a72', 'https://media.liche.cn/meijiaka-zy/materials/18299f5241fa48599dadd2c23f8d1a72.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要反弹器' AND level = 3), '73aa3d445ac9404b838ff0dca9ac701a', 'https://media.liche.cn/meijiaka-zy/materials/73aa3d445ac9404b838ff0dca9ac701a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要简约背景墙' AND level = 3), '3fd83f35484844839aaea34cf17793eb', 'https://media.liche.cn/meijiaka-zy/materials/3fd83f35484844839aaea34cf17793eb.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要反弹器' AND level = 3), '10d03f43eb624306abb9ea6fea5346c4', 'https://media.liche.cn/meijiaka-zy/materials/10d03f43eb624306abb9ea6fea5346c4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要反弹器' AND level = 3), '63728a0571634d0082165d6a37cf2cf8', 'https://media.liche.cn/meijiaka-zy/materials/63728a0571634d0082165d6a37cf2cf8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'cb93c6a5ea4849a2b1af5a272ba1ba85', 'https://media.liche.cn/meijiaka-zy/materials/cb93c6a5ea4849a2b1af5a272ba1ba85.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直吸马桶' AND level = 3), 'daa1ce258aaa45a08088bc925128abdd', 'https://media.liche.cn/meijiaka-zy/materials/daa1ce258aaa45a08088bc925128abdd.mp4', 5.37, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直吸马桶' AND level = 3), 'bb734d2459ae4095a28e5de81cec0c95', 'https://media.liche.cn/meijiaka-zy/materials/bb734d2459ae4095a28e5de81cec0c95.mp4', 5.07, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'bf8647bc127c4a83a3bdc05f9b58cf86', 'https://media.liche.cn/meijiaka-zy/materials/bf8647bc127c4a83a3bdc05f9b58cf86.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), '340071a0891d44b186ed0ef05a0d612f', 'https://media.liche.cn/meijiaka-zy/materials/340071a0891d44b186ed0ef05a0d612f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'b3d5d891960e493ab63da223e4095aee', 'https://media.liche.cn/meijiaka-zy/materials/b3d5d891960e493ab63da223e4095aee.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), '457d8ad107d842b484f69ef1bd4ab5d5', 'https://media.liche.cn/meijiaka-zy/materials/457d8ad107d842b484f69ef1bd4ab5d5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直吸马桶' AND level = 3), 'd74fc12f0e67405189e589349d9625a7', 'https://media.liche.cn/meijiaka-zy/materials/d74fc12f0e67405189e589349d9625a7.mp4', 8.17, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), '18979aaba27f46caa104ea3889a95af5', 'https://media.liche.cn/meijiaka-zy/materials/18979aaba27f46caa104ea3889a95af5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '0912d19ef6ce4484b73dba867cf3623f', 'https://media.liche.cn/meijiaka-zy/materials/0912d19ef6ce4484b73dba867cf3623f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'e5f132a76d7b4876b800829df30beb72', 'https://media.liche.cn/meijiaka-zy/materials/e5f132a76d7b4876b800829df30beb72.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'a70090f917e547928e99ae70176553ec', 'https://media.liche.cn/meijiaka-zy/materials/a70090f917e547928e99ae70176553ec.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'f2bf76d6bd6b4eccbca32d5b8eee1b25', 'https://media.liche.cn/meijiaka-zy/materials/f2bf76d6bd6b4eccbca32d5b8eee1b25.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '676c0eba61bc4e17921c3e47bc046285', 'https://media.liche.cn/meijiaka-zy/materials/676c0eba61bc4e17921c3e47bc046285.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '4ce8607f029f477895e7fbd6bbe5d8f5', 'https://media.liche.cn/meijiaka-zy/materials/4ce8607f029f477895e7fbd6bbe5d8f5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'd8908c3eb50f4defaab2f80f623ff48e', 'https://media.liche.cn/meijiaka-zy/materials/d8908c3eb50f4defaab2f80f623ff48e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '51e7e73707644cf3bbd496ac68c4bf1c', 'https://media.liche.cn/meijiaka-zy/materials/51e7e73707644cf3bbd496ac68c4bf1c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'fa90db59ff1a4679a9ab1ce03216cbb7', 'https://media.liche.cn/meijiaka-zy/materials/fa90db59ff1a4679a9ab1ce03216cbb7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '9fd5b0f08038423588c000354d853ebc', 'https://media.liche.cn/meijiaka-zy/materials/9fd5b0f08038423588c000354d853ebc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'a0dbe2342d9648eba251d44d943a982e', 'https://media.liche.cn/meijiaka-zy/materials/a0dbe2342d9648eba251d44d943a982e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要洗烘套装' AND level = 3), 'b4089f8aca264ab29ce0c735bbd8c971', 'https://media.liche.cn/meijiaka-zy/materials/b4089f8aca264ab29ce0c735bbd8c971.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'daf2e02c2c244816abd17d7985000ddc', 'https://media.liche.cn/meijiaka-zy/materials/daf2e02c2c244816abd17d7985000ddc.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'd3dc878a450a4e9abc33348c60a3ab60', 'https://media.liche.cn/meijiaka-zy/materials/d3dc878a450a4e9abc33348c60a3ab60.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '4add493565054addaeb7e62f92781253', 'https://media.liche.cn/meijiaka-zy/materials/4add493565054addaeb7e62f92781253.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '2eb71d90d3954467a845bf624978affd', 'https://media.liche.cn/meijiaka-zy/materials/2eb71d90d3954467a845bf624978affd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'bd625cb9279146dc81037ea6ff5e1624', 'https://media.liche.cn/meijiaka-zy/materials/bd625cb9279146dc81037ea6ff5e1624.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '80a1b08f14894b089d638150fadbd0ad', 'https://media.liche.cn/meijiaka-zy/materials/80a1b08f14894b089d638150fadbd0ad.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '614eff6420174661b7232fef116f086e', 'https://media.liche.cn/meijiaka-zy/materials/614eff6420174661b7232fef116f086e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '714240eb1ac540cda61431169d04f6c2', 'https://media.liche.cn/meijiaka-zy/materials/714240eb1ac540cda61431169d04f6c2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直吸马桶' AND level = 3), 'f2b7a8a7a357488a86950c9dfaaece4a', 'https://media.liche.cn/meijiaka-zy/materials/f2b7a8a7a357488a86950c9dfaaece4a.mp4', 10.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '0c252682fba544a4b2f60c467b8d2d89', 'https://media.liche.cn/meijiaka-zy/materials/0c252682fba544a4b2f60c467b8d2d89.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直吸马桶' AND level = 3), '4c121213b6014ca090dcf55a872529f1', 'https://media.liche.cn/meijiaka-zy/materials/4c121213b6014ca090dcf55a872529f1.mp4', 13.53, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), '6fa12970f6b44af69b40a5f8d8149f23', 'https://media.liche.cn/meijiaka-zy/materials/6fa12970f6b44af69b40a5f8d8149f23.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要封闭式收纳柜' AND level = 3), 'd982ced9cbec40ab95b6a6bb5f37f396', 'https://media.liche.cn/meijiaka-zy/materials/d982ced9cbec40ab95b6a6bb5f37f396.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), 'fcb2e181a47244aba544d30a4b601e27', 'https://media.liche.cn/meijiaka-zy/materials/fcb2e181a47244aba544d30a4b601e27.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), 'e3d327c9bcde475c9982d14ad8136806', 'https://media.liche.cn/meijiaka-zy/materials/e3d327c9bcde475c9982d14ad8136806.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), 'fda39bb3c9174004b2c3d19232d4254b', 'https://media.liche.cn/meijiaka-zy/materials/fda39bb3c9174004b2c3d19232d4254b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), 'c7f836a67d1b47ddb246e64be9313b8d', 'https://media.liche.cn/meijiaka-zy/materials/c7f836a67d1b47ddb246e64be9313b8d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), 'c20358ac4a7a49cfae14aefe6309ac01', 'https://media.liche.cn/meijiaka-zy/materials/c20358ac4a7a49cfae14aefe6309ac01.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), '1a301ce4004f4f4d8880e58fc0dccfba', 'https://media.liche.cn/meijiaka-zy/materials/1a301ce4004f4f4d8880e58fc0dccfba.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要普通门锁' AND level = 3), 'a1c4505161544670829bfcedfe3c17ab', 'https://media.liche.cn/meijiaka-zy/materials/a1c4505161544670829bfcedfe3c17ab.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), '2b73b0b7d4ba4a9f83bdb550ec808daa', 'https://media.liche.cn/meijiaka-zy/materials/2b73b0b7d4ba4a9f83bdb550ec808daa.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), '761468575b654a9aa47bb25c1e1cfc03', 'https://media.liche.cn/meijiaka-zy/materials/761468575b654a9aa47bb25c1e1cfc03.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), '328e8a938cd74d079fb7502eade3be13', 'https://media.liche.cn/meijiaka-zy/materials/328e8a938cd74d079fb7502eade3be13.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), 'fb67b18c9aae4a55b92e6263883ffcf1', 'https://media.liche.cn/meijiaka-zy/materials/fb67b18c9aae4a55b92e6263883ffcf1.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), '531d627c80614b30b3607ece1669ce50', 'https://media.liche.cn/meijiaka-zy/materials/531d627c80614b30b3607ece1669ce50.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋通铺' AND level = 3), '26c3d13ce1c84773ae48b78c12f18a63', 'https://media.liche.cn/meijiaka-zy/materials/26c3d13ce1c84773ae48b78c12f18a63.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), 'd0d96214b306481dadc102d613e25f5f', 'https://media.liche.cn/meijiaka-zy/materials/d0d96214b306481dadc102d613e25f5f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), '489870056f38446cafad5e56e867aa81', 'https://media.liche.cn/meijiaka-zy/materials/489870056f38446cafad5e56e867aa81.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), 'c5f4575ec4ee4acaa4dc86f4e143abf6', 'https://media.liche.cn/meijiaka-zy/materials/c5f4575ec4ee4acaa4dc86f4e143abf6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), '4954ed56ecee466988ddbcd25340ecbf', 'https://media.liche.cn/meijiaka-zy/materials/4954ed56ecee466988ddbcd25340ecbf.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要智能门锁' AND level = 3), 'e144c9d7ac4e4bf085fd1ba495419b95', 'https://media.liche.cn/meijiaka-zy/materials/e144c9d7ac4e4bf085fd1ba495419b95.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), 'a6bf831b10614b17a725a72b192f1d8f', 'https://media.liche.cn/meijiaka-zy/materials/a6bf831b10614b17a725a72b192f1d8f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), '3e4ac934a94546eab0c28a613b728924', 'https://media.liche.cn/meijiaka-zy/materials/3e4ac934a94546eab0c28a613b728924.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), '7df45401d3b14fb8bb6e1e6795e6308e', 'https://media.liche.cn/meijiaka-zy/materials/7df45401d3b14fb8bb6e1e6795e6308e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), 'c5530dcbf9e841698d2d4e87234a9ee3', 'https://media.liche.cn/meijiaka-zy/materials/c5530dcbf9e841698d2d4e87234a9ee3.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), '78c47ecace81435685914ed734a9aad6', 'https://media.liche.cn/meijiaka-zy/materials/78c47ecace81435685914ed734a9aad6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), 'b6c819c9e3a84c1b925e1389d03a2228', 'https://media.liche.cn/meijiaka-zy/materials/b6c819c9e3a84c1b925e1389d03a2228.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), '8e3fe60b156d46cab7e72638f3e6d4c0', 'https://media.liche.cn/meijiaka-zy/materials/8e3fe60b156d46cab7e72638f3e6d4c0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), '61e8f13fa4784de799291b6729efecf4', 'https://media.liche.cn/meijiaka-zy/materials/61e8f13fa4784de799291b6729efecf4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), '3740b0186d9f47ae89dc285fc1e0b49f', 'https://media.liche.cn/meijiaka-zy/materials/3740b0186d9f47ae89dc285fc1e0b49f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), 'bbb66f1a1f6247dc8c1217fd84c8a2f0', 'https://media.liche.cn/meijiaka-zy/materials/bbb66f1a1f6247dc8c1217fd84c8a2f0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要推拉门' AND level = 3), '3b4e44089bb94973940fa26275e40c36', 'https://media.liche.cn/meijiaka-zy/materials/3b4e44089bb94973940fa26275e40c36.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), 'a38b481189084dbdaf042e2a7b807587', 'https://media.liche.cn/meijiaka-zy/materials/a38b481189084dbdaf042e2a7b807587.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '72c68ef87d4d467394907366bd96adf3', 'https://media.liche.cn/meijiaka-zy/materials/72c68ef87d4d467394907366bd96adf3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '2306f7080a9f418393b9edba0d402f5d', 'https://media.liche.cn/meijiaka-zy/materials/2306f7080a9f418393b9edba0d402f5d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '79407fb523b5410e8e4c0f74d80d9def', 'https://media.liche.cn/meijiaka-zy/materials/79407fb523b5410e8e4c0f74d80d9def.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '83f6235e48b64a87a05865c9e9db90a6', 'https://media.liche.cn/meijiaka-zy/materials/83f6235e48b64a87a05865c9e9db90a6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), 'eb8ab62a87674908a068558ba059a815', 'https://media.liche.cn/meijiaka-zy/materials/eb8ab62a87674908a068558ba059a815.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '4fed27bcb53049c3b2b99f4e8a171ce4', 'https://media.liche.cn/meijiaka-zy/materials/4fed27bcb53049c3b2b99f4e8a171ce4.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '23ccfdac611f451faad7dc0959a58f81', 'https://media.liche.cn/meijiaka-zy/materials/23ccfdac611f451faad7dc0959a58f81.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '44614bf08fde4c9f8bdff970f6fe2d23', 'https://media.liche.cn/meijiaka-zy/materials/44614bf08fde4c9f8bdff970f6fe2d23.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '78b23201cf4d4e59955b197dd7bb27b6', 'https://media.liche.cn/meijiaka-zy/materials/78b23201cf4d4e59955b197dd7bb27b6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), 'dff223a1485641d9bd3df72e99d6d8b0', 'https://media.liche.cn/meijiaka-zy/materials/dff223a1485641d9bd3df72e99d6d8b0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), 'f2457ab95e1043beadb85948a9401769', 'https://media.liche.cn/meijiaka-zy/materials/f2457ab95e1043beadb85948a9401769.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '8a06ce9d21024c149097cd32addf3f64', 'https://media.liche.cn/meijiaka-zy/materials/8a06ce9d21024c149097cd32addf3f64.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '86791cc9d8694395ab4f7ac8015b8df9', 'https://media.liche.cn/meijiaka-zy/materials/86791cc9d8694395ab4f7ac8015b8df9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地电视柜' AND level = 3), '55b2c96f9daf4299b22892bbb602c6fe', 'https://media.liche.cn/meijiaka-zy/materials/55b2c96f9daf4299b22892bbb602c6fe.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '3fe3a28435174b8790be42bbbf4a0a86', 'https://media.liche.cn/meijiaka-zy/materials/3fe3a28435174b8790be42bbbf4a0a86.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), 'a034ffe097434cb69bc6b55222ad767d', 'https://media.liche.cn/meijiaka-zy/materials/a034ffe097434cb69bc6b55222ad767d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '65866b3a251d4abab6e0e0326e033830', 'https://media.liche.cn/meijiaka-zy/materials/65866b3a251d4abab6e0e0326e033830.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '21cdd0d93ef0408a8d147efc483c3db2', 'https://media.liche.cn/meijiaka-zy/materials/21cdd0d93ef0408a8d147efc483c3db2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '28a455d2dbda4b71b45961cb7d6df065', 'https://media.liche.cn/meijiaka-zy/materials/28a455d2dbda4b71b45961cb7d6df065.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), 'a84807c12a0740aeb6082842f959bfad', 'https://media.liche.cn/meijiaka-zy/materials/a84807c12a0740aeb6082842f959bfad.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), '11ec803703e247278aa36ca85c791f86', 'https://media.liche.cn/meijiaka-zy/materials/11ec803703e247278aa36ca85c791f86.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双包套' AND level = 3), 'fa99f723c173436ca904646f39602830', 'https://media.liche.cn/meijiaka-zy/materials/fa99f723c173436ca904646f39602830.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '2058716ee3784eab8bd387fff90360ea', 'https://media.liche.cn/meijiaka-zy/materials/2058716ee3784eab8bd387fff90360ea.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '9b6e4c35b7b642809b1aee242d42a640', 'https://media.liche.cn/meijiaka-zy/materials/9b6e4c35b7b642809b1aee242d42a640.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '3ffbd0afbc5a497fb58fdf21ed68fd7d', 'https://media.liche.cn/meijiaka-zy/materials/3ffbd0afbc5a497fb58fdf21ed68fd7d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '8d58026f0bc14debb2c0ae145afcf8bd', 'https://media.liche.cn/meijiaka-zy/materials/8d58026f0bc14debb2c0ae145afcf8bd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), 'd8f88540a4b44d7f8077ac66384dc023', 'https://media.liche.cn/meijiaka-zy/materials/d8f88540a4b44d7f8077ac66384dc023.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '1e73f9411abc4c1483460fdbcdaf0fd8', 'https://media.liche.cn/meijiaka-zy/materials/1e73f9411abc4c1483460fdbcdaf0fd8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要单包套' AND level = 3), '8f9534ada9b1407a8d63af2ecade04b8', 'https://media.liche.cn/meijiaka-zy/materials/8f9534ada9b1407a8d63af2ecade04b8.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), 'bf63f61a9e50408e94c92dcb232222be', 'https://media.liche.cn/meijiaka-zy/materials/bf63f61a9e50408e94c92dcb232222be.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), '73cfc4354cd0454eabafe304d5ecdfde', 'https://media.liche.cn/meijiaka-zy/materials/73cfc4354cd0454eabafe304d5ecdfde.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), '2b7d098930c54cc4999c65f2087c88a5', 'https://media.liche.cn/meijiaka-zy/materials/2b7d098930c54cc4999c65f2087c88a5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), '0fb4a9321caa48a6a4a8c28f787fd2ce', 'https://media.liche.cn/meijiaka-zy/materials/0fb4a9321caa48a6a4a8c28f787fd2ce.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), 'c753699fd169499cace1251654b3c3b0', 'https://media.liche.cn/meijiaka-zy/materials/c753699fd169499cace1251654b3c3b0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), '9a3cb1a64eaf44afba705a5b55cd23a2', 'https://media.liche.cn/meijiaka-zy/materials/9a3cb1a64eaf44afba705a5b55cd23a2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), 'caaa75dc958a403a9b6238ab7f51e5ea', 'https://media.liche.cn/meijiaka-zy/materials/caaa75dc958a403a9b6238ab7f51e5ea.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要海棠角' AND level = 3), 'c16e7ecedada4320a1b2f543d7da388c', 'https://media.liche.cn/meijiaka-zy/materials/c16e7ecedada4320a1b2f543d7da388c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), '68a6d1f2c69a4e1580a510f7b94c6c69', 'https://media.liche.cn/meijiaka-zy/materials/68a6d1f2c69a4e1580a510f7b94c6c69.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), 'f62dcbc4180d4350acd02c6c4b667f6d', 'https://media.liche.cn/meijiaka-zy/materials/f62dcbc4180d4350acd02c6c4b667f6d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), '6fbc5117b1244d249e0d6be794b08d45', 'https://media.liche.cn/meijiaka-zy/materials/6fbc5117b1244d249e0d6be794b08d45.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要大单槽' AND level = 3), '7d1ad41072d64d309490d7ccdfcab854', 'https://media.liche.cn/meijiaka-zy/materials/7d1ad41072d64d309490d7ccdfcab854.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), '0429d922479f4094888995d7bde95974', 'https://media.liche.cn/meijiaka-zy/materials/0429d922479f4094888995d7bde95974.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要墙排下水' AND level = 3), '6213d780cbd14e6589dfffae7926de6e', 'https://media.liche.cn/meijiaka-zy/materials/6213d780cbd14e6589dfffae7926de6e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要大单槽' AND level = 3), 'fe60d0671011412097721670e23f7a1a', 'https://media.liche.cn/meijiaka-zy/materials/fe60d0671011412097721670e23f7a1a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要斜五孔插座' AND level = 3), '215b01e4c3404692a8f3c4dbd3020763', 'https://media.liche.cn/meijiaka-zy/materials/215b01e4c3404692a8f3c4dbd3020763.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要大单槽' AND level = 3), '86f027ce15f343b6a6fb6a68cd41e0ef', 'https://media.liche.cn/meijiaka-zy/materials/86f027ce15f343b6a6fb6a68cd41e0ef.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要大单槽' AND level = 3), '0a71c8791f9b46569af8b9ab3f857a70', 'https://media.liche.cn/meijiaka-zy/materials/0a71c8791f9b46569af8b9ab3f857a70.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要大单槽' AND level = 3), '8fd0556ac84e4dfe95076944a3ea26f6', 'https://media.liche.cn/meijiaka-zy/materials/8fd0556ac84e4dfe95076944a3ea26f6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要免拉手' AND level = 3), 'b6422a739f034d698c4633c50e3696f5', 'https://media.liche.cn/meijiaka-zy/materials/b6422a739f034d698c4633c50e3696f5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要斜五孔插座' AND level = 3), '47cb1b4b90614208b623204a367c8894', 'https://media.liche.cn/meijiaka-zy/materials/47cb1b4b90614208b623204a367c8894.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要斜五孔插座' AND level = 3), 'ac313cd6eb8e4502b42d6fe6b6289568', 'https://media.liche.cn/meijiaka-zy/materials/ac313cd6eb8e4502b42d6fe6b6289568.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要斜五孔插座' AND level = 3), '91a976beea5047ddad2ec4bee363ea0c', 'https://media.liche.cn/meijiaka-zy/materials/91a976beea5047ddad2ec4bee363ea0c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要免拉手' AND level = 3), 'ff5fa077f3c147c189a093bbb1fb266b', 'https://media.liche.cn/meijiaka-zy/materials/ff5fa077f3c147c189a093bbb1fb266b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要斜五孔插座' AND level = 3), 'cff27b5a106c473b8d932c8c79c2ca50', 'https://media.liche.cn/meijiaka-zy/materials/cff27b5a106c473b8d932c8c79c2ca50.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要免拉手' AND level = 3), '6c347f6ec050425e8dd3c0a685bfc864', 'https://media.liche.cn/meijiaka-zy/materials/6c347f6ec050425e8dd3c0a685bfc864.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要免拉手' AND level = 3), '8fd2ef2d81ca4a8493e077fead5be7f6', 'https://media.liche.cn/meijiaka-zy/materials/8fd2ef2d81ca4a8493e077fead5be7f6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '5e83b06f477f45ac8b7a7e34f90885a9', 'https://media.liche.cn/meijiaka-zy/materials/5e83b06f477f45ac8b7a7e34f90885a9.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '8669474e3c5a497e81c0487057ab3589', 'https://media.liche.cn/meijiaka-zy/materials/8669474e3c5a497e81c0487057ab3589.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要免拉手' AND level = 3), '428ef63a76af4973953b152b43df083e', 'https://media.liche.cn/meijiaka-zy/materials/428ef63a76af4973953b152b43df083e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), 'aa01ff4042394da89aaf49ddd859c25a', 'https://media.liche.cn/meijiaka-zy/materials/aa01ff4042394da89aaf49ddd859c25a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '1bf52ea432254763a4be7c3aafc2a7ab', 'https://media.liche.cn/meijiaka-zy/materials/1bf52ea432254763a4be7c3aafc2a7ab.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '92287c55523f4a52a8cd0001be7acfd0', 'https://media.liche.cn/meijiaka-zy/materials/92287c55523f4a52a8cd0001be7acfd0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '695c249ae9d34e748b55c9dcf813d605', 'https://media.liche.cn/meijiaka-zy/materials/695c249ae9d34e748b55c9dcf813d605.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), 'd3818b3db3bb4859997a0bb967dcbc1e', 'https://media.liche.cn/meijiaka-zy/materials/d3818b3db3bb4859997a0bb967dcbc1e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), 'd9b6837cc6a74945a867993fbfcdd0f1', 'https://media.liche.cn/meijiaka-zy/materials/d9b6837cc6a74945a867993fbfcdd0f1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '8cc9a2ab7adc41c6bc9ba9da81b517a0', 'https://media.liche.cn/meijiaka-zy/materials/8cc9a2ab7adc41c6bc9ba9da81b517a0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '0fbf457d91fe45d0a320037278ff9dc3', 'https://media.liche.cn/meijiaka-zy/materials/0fbf457d91fe45d0a320037278ff9dc3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '7774189b34f948e8bdfd0a8a84201730', 'https://media.liche.cn/meijiaka-zy/materials/7774189b34f948e8bdfd0a8a84201730.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '5a4eacf9a1c84f668ce34a5178f09c55', 'https://media.liche.cn/meijiaka-zy/materials/5a4eacf9a1c84f668ce34a5178f09c55.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), 'c5d5fff32dfc4ba2aab6f2112967771d', 'https://media.liche.cn/meijiaka-zy/materials/c5d5fff32dfc4ba2aab6f2112967771d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '31348f533a0d47558d189e8e4fd57614', 'https://media.liche.cn/meijiaka-zy/materials/31348f533a0d47558d189e8e4fd57614.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), 'b0c1094e71244b0d9d8f03e3825d4ece', 'https://media.liche.cn/meijiaka-zy/materials/b0c1094e71244b0d9d8f03e3825d4ece.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), 'cdb95ebc69dc4a3eb85815008c1137df', 'https://media.liche.cn/meijiaka-zy/materials/cdb95ebc69dc4a3eb85815008c1137df.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), 'abcb44bd76c2432285e0eb7d9d2f0824', 'https://media.liche.cn/meijiaka-zy/materials/abcb44bd76c2432285e0eb7d9d2f0824.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), 'cf959fae9b5949b38599a14240ec8849', 'https://media.liche.cn/meijiaka-zy/materials/cf959fae9b5949b38599a14240ec8849.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '5b3525ed5250460e934b9256b9cc665f', 'https://media.liche.cn/meijiaka-zy/materials/5b3525ed5250460e934b9256b9cc665f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '676a083457a547d9aaeca4143a205d90', 'https://media.liche.cn/meijiaka-zy/materials/676a083457a547d9aaeca4143a205d90.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '8f16e475f0e3497882ce60b09f8cc418', 'https://media.liche.cn/meijiaka-zy/materials/8f16e475f0e3497882ce60b09f8cc418.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '433504cc52164a64b30c63f523a8cbdd', 'https://media.liche.cn/meijiaka-zy/materials/433504cc52164a64b30c63f523a8cbdd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要无主灯' AND level = 3), '1c1d72ce6d454662b2a22f3b88bd447f', 'https://media.liche.cn/meijiaka-zy/materials/1c1d72ce6d454662b2a22f3b88bd447f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要十字开门冰箱' AND level = 3), '21fda56f23fc4d8e8842cd9e7101ed65', 'https://media.liche.cn/meijiaka-zy/materials/21fda56f23fc4d8e8842cd9e7101ed65.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), '25133f2ecbeb4c8abc921ecf1bd8e9c7', 'https://media.liche.cn/meijiaka-zy/materials/25133f2ecbeb4c8abc921ecf1bd8e9c7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), '45b80d5d87d6409d8abce8babefe104c', 'https://media.liche.cn/meijiaka-zy/materials/45b80d5d87d6409d8abce8babefe104c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), 'a6ae11f09d18479aa309b844c4e05036', 'https://media.liche.cn/meijiaka-zy/materials/a6ae11f09d18479aa309b844c4e05036.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), '901301727c0f4767bef0773e71710e06', 'https://media.liche.cn/meijiaka-zy/materials/901301727c0f4767bef0773e71710e06.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), 'e73abb7f12014b87a2c568bdf53498e8', 'https://media.liche.cn/meijiaka-zy/materials/e73abb7f12014b87a2c568bdf53498e8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), '6bf9ef12a8ec4b278fdfd21a402846b7', 'https://media.liche.cn/meijiaka-zy/materials/6bf9ef12a8ec4b278fdfd21a402846b7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), 'a88a9113f57a4f7eb99e6143cc58bcf4', 'https://media.liche.cn/meijiaka-zy/materials/a88a9113f57a4f7eb99e6143cc58bcf4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), 'fa483fde6b404e60a39c5429941a867b', 'https://media.liche.cn/meijiaka-zy/materials/fa483fde6b404e60a39c5429941a867b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要一体式卫生间' AND level = 3), 'e7a182a774d140ce8c71552756b74534', 'https://media.liche.cn/meijiaka-zy/materials/e7a182a774d140ce8c71552756b74534.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), '57ce8cb169b04a019f01d2fd638f5d34', 'https://media.liche.cn/meijiaka-zy/materials/57ce8cb169b04a019f01d2fd638f5d34.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), '2c13ee35c18c45c2964db46e72676373', 'https://media.liche.cn/meijiaka-zy/materials/2c13ee35c18c45c2964db46e72676373.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), '40ade9ad465f41e19d2eb2cec01da54a', 'https://media.liche.cn/meijiaka-zy/materials/40ade9ad465f41e19d2eb2cec01da54a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), 'c52612a164ce4a40a85959768a6d9fc3', 'https://media.liche.cn/meijiaka-zy/materials/c52612a164ce4a40a85959768a6d9fc3.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要阳角条' AND level = 3), 'aa3301ac27d04d82b71f13dde321eb64', 'https://media.liche.cn/meijiaka-zy/materials/aa3301ac27d04d82b71f13dde321eb64.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要纯色窗帘' AND level = 3), '7f8aabc9e1f14fbaa1dd021c396f5132', 'https://media.liche.cn/meijiaka-zy/materials/7f8aabc9e1f14fbaa1dd021c396f5132.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要纯色窗帘' AND level = 3), '33eab2328c80418f9ee913d38d4d6e82', 'https://media.liche.cn/meijiaka-zy/materials/33eab2328c80418f9ee913d38d4d6e82.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要纯色窗帘' AND level = 3), '95992a991cc14ce0a914660d08b52ba2', 'https://media.liche.cn/meijiaka-zy/materials/95992a991cc14ce0a914660d08b52ba2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要纯色窗帘' AND level = 3), 'c50e3bc450624a878c944341af049311', 'https://media.liche.cn/meijiaka-zy/materials/c50e3bc450624a878c944341af049311.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), 'a5950953d7744f79beb5db9609ff6f3f', 'https://media.liche.cn/meijiaka-zy/materials/a5950953d7744f79beb5db9609ff6f3f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要纯色窗帘' AND level = 3), '54384ba934954b25965a74034c0eb6fa', 'https://media.liche.cn/meijiaka-zy/materials/54384ba934954b25965a74034c0eb6fa.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), '7f84182969944738b3c7991f07313781', 'https://media.liche.cn/meijiaka-zy/materials/7f84182969944738b3c7991f07313781.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), 'ce921dfe512a4652b5bc0f82eb14f1a6', 'https://media.liche.cn/meijiaka-zy/materials/ce921dfe512a4652b5bc0f82eb14f1a6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), 'a40215e0f6564cdba127bf4740cbc8ad', 'https://media.liche.cn/meijiaka-zy/materials/a40215e0f6564cdba127bf4740cbc8ad.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), 'ad7db50f48224c2cb983aa938072e7db', 'https://media.liche.cn/meijiaka-zy/materials/ad7db50f48224c2cb983aa938072e7db.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要集成灶' AND level = 3), '598068a152084afba80138bf241ad710', 'https://media.liche.cn/meijiaka-zy/materials/598068a152084afba80138bf241ad710.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要筒灯' AND level = 3), '2c877e88d4474db8b831c2924f761b1e', 'https://media.liche.cn/meijiaka-zy/materials/2c877e88d4474db8b831c2924f761b1e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要筒灯' AND level = 3), 'ce181390333740c79f797085053b44a4', 'https://media.liche.cn/meijiaka-zy/materials/ce181390333740c79f797085053b44a4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要筒灯' AND level = 3), '2b0d28af29044de0b81417025962ef19', 'https://media.liche.cn/meijiaka-zy/materials/2b0d28af29044de0b81417025962ef19.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要筒灯' AND level = 3), '28913e5598d54178a706fe5be074a4a6', 'https://media.liche.cn/meijiaka-zy/materials/28913e5598d54178a706fe5be074a4a6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要筒灯' AND level = 3), '2e361449d69b4ca1ac190926b39bef60', 'https://media.liche.cn/meijiaka-zy/materials/2e361449d69b4ca1ac190926b39bef60.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '5ebf20ac1a904e9c829102bed8f231d9', 'https://media.liche.cn/meijiaka-zy/materials/5ebf20ac1a904e9c829102bed8f231d9.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '419b9163483d4b13bd2c9e33aeb69bb7', 'https://media.liche.cn/meijiaka-zy/materials/419b9163483d4b13bd2c9e33aeb69bb7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '64d57590189749308ea0618a624e8c05', 'https://media.liche.cn/meijiaka-zy/materials/64d57590189749308ea0618a624e8c05.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '83c853f4dae449dcab8dd593341f051e', 'https://media.liche.cn/meijiaka-zy/materials/83c853f4dae449dcab8dd593341f051e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '9591b72ad2a44dbf9fdcee63626c75f2', 'https://media.liche.cn/meijiaka-zy/materials/9591b72ad2a44dbf9fdcee63626c75f2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), 'baff9a0a1dd047a7937b452cf0b9f336', 'https://media.liche.cn/meijiaka-zy/materials/baff9a0a1dd047a7937b452cf0b9f336.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '4146684128eb458eb5d489fe8c7358e6', 'https://media.liche.cn/meijiaka-zy/materials/4146684128eb458eb5d489fe8c7358e6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '4c6e7097e1044c23826cb96c41185983', 'https://media.liche.cn/meijiaka-zy/materials/4c6e7097e1044c23826cb96c41185983.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要双开门冰箱' AND level = 3), '09c00bde37f94589b69b3f0efe1835f3', 'https://media.liche.cn/meijiaka-zy/materials/09c00bde37f94589b69b3f0efe1835f3.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要路由器' AND level = 3), 'f7bb7c1755b44957859410b2d4951466', 'https://media.liche.cn/meijiaka-zy/materials/f7bb7c1755b44957859410b2d4951466.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂背景墙' AND level = 3), 'e36fd2eadfe84571bdbf945a973fd976', 'https://media.liche.cn/meijiaka-zy/materials/e36fd2eadfe84571bdbf945a973fd976.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂背景墙' AND level = 3), '91a6bed1614346699aabe3d082fdb803', 'https://media.liche.cn/meijiaka-zy/materials/91a6bed1614346699aabe3d082fdb803.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂背景墙' AND level = 3), 'c815b7b7c4ad435987a35ec9b6d45410', 'https://media.liche.cn/meijiaka-zy/materials/c815b7b7c4ad435987a35ec9b6d45410.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂背景墙' AND level = 3), '0c6be4f2b9a9420089fcf2331dba2089', 'https://media.liche.cn/meijiaka-zy/materials/0c6be4f2b9a9420089fcf2331dba2089.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要复杂背景墙' AND level = 3), '622ab2b084f3455d8492b6ff9049da9a', 'https://media.liche.cn/meijiaka-zy/materials/622ab2b084f3455d8492b6ff9049da9a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要路由器' AND level = 3), '64d288b931434d089d01424575eeac10', 'https://media.liche.cn/meijiaka-zy/materials/64d288b931434d089d01424575eeac10.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '2878239db13c4af39cea212212562009', 'https://media.liche.cn/meijiaka-zy/materials/2878239db13c4af39cea212212562009.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要路由器' AND level = 3), '7a89b6752a3b4446baf41ee13430bfd7', 'https://media.liche.cn/meijiaka-zy/materials/7a89b6752a3b4446baf41ee13430bfd7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要路由器' AND level = 3), '1711b9adc3e5451191ec4df6d7651818', 'https://media.liche.cn/meijiaka-zy/materials/1711b9adc3e5451191ec4df6d7651818.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '5b0b6196f2c943b19327e4f2a69a8dc0', 'https://media.liche.cn/meijiaka-zy/materials/5b0b6196f2c943b19327e4f2a69a8dc0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '33c2cbb7e88a4cdeaff34f3d833fd590', 'https://media.liche.cn/meijiaka-zy/materials/33c2cbb7e88a4cdeaff34f3d833fd590.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要路由器' AND level = 3), '59b53238efbc47f5bcd371c2b7ecaf45', 'https://media.liche.cn/meijiaka-zy/materials/59b53238efbc47f5bcd371c2b7ecaf45.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '57e000c537c84880b9ba994ce51741d9', 'https://media.liche.cn/meijiaka-zy/materials/57e000c537c84880b9ba994ce51741d9.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), 'ff051b628d8845a6b039636e40692df1', 'https://media.liche.cn/meijiaka-zy/materials/ff051b628d8845a6b039636e40692df1.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '274332f22bc84a7fb8bb9e53b119967a', 'https://media.liche.cn/meijiaka-zy/materials/274332f22bc84a7fb8bb9e53b119967a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), 'd4c56e2483a94e2dadf4e9923fa8e28d', 'https://media.liche.cn/meijiaka-zy/materials/d4c56e2483a94e2dadf4e9923fa8e28d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), '2471841af1aa47e6bc51acca7996296b', 'https://media.liche.cn/meijiaka-zy/materials/2471841af1aa47e6bc51acca7996296b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), '9ecfb42c03e64fda9148ad20e4425cd7', 'https://media.liche.cn/meijiaka-zy/materials/9ecfb42c03e64fda9148ad20e4425cd7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要瓷砖上墙' AND level = 3), '7f254d8e766940db97fb9036c1b2073c', 'https://media.liche.cn/meijiaka-zy/materials/7f254d8e766940db97fb9036c1b2073c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), '88095b798d554c1a9d6731779af55714', 'https://media.liche.cn/meijiaka-zy/materials/88095b798d554c1a9d6731779af55714.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), 'e6c6aa1e88574e3a9a7334dc55c9dede', 'https://media.liche.cn/meijiaka-zy/materials/e6c6aa1e88574e3a9a7334dc55c9dede.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), '07baf40032f34e4fadcc3ef93700a854', 'https://media.liche.cn/meijiaka-zy/materials/07baf40032f34e4fadcc3ef93700a854.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), 'e7405d0b3d694980a891ad458fa16b52', 'https://media.liche.cn/meijiaka-zy/materials/e7405d0b3d694980a891ad458fa16b52.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), '1ccd11c09ab74530a00e1b24bab34461', 'https://media.liche.cn/meijiaka-zy/materials/1ccd11c09ab74530a00e1b24bab34461.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), 'cc7104e90ada44e5a066b64d4e404bbe', 'https://media.liche.cn/meijiaka-zy/materials/cc7104e90ada44e5a066b64d4e404bbe.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要打通阳台' AND level = 3), 'c0978673ab814f05997cd635cedb06c2', 'https://media.liche.cn/meijiaka-zy/materials/c0978673ab814f05997cd635cedb06c2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), 'ed544b523dee45ed89cc00a152a20e22', 'https://media.liche.cn/meijiaka-zy/materials/ed544b523dee45ed89cc00a152a20e22.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '9ae5f8d028a445499bcafcbbe2203125', 'https://media.liche.cn/meijiaka-zy/materials/9ae5f8d028a445499bcafcbbe2203125.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '163aef9d77af4683848b432418379f29', 'https://media.liche.cn/meijiaka-zy/materials/163aef9d77af4683848b432418379f29.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), '24da8d6808bb40079fe6102df8e77c42', 'https://media.liche.cn/meijiaka-zy/materials/24da8d6808bb40079fe6102df8e77c42.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), 'd723bcd2370a4b4686d9ef6bfc36593e', 'https://media.liche.cn/meijiaka-zy/materials/d723bcd2370a4b4686d9ef6bfc36593e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), '3526f0a974f94961bb3241e0c1435bf5', 'https://media.liche.cn/meijiaka-zy/materials/3526f0a974f94961bb3241e0c1435bf5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '3e352ee16a304427bdfe5178bd4c9471', 'https://media.liche.cn/meijiaka-zy/materials/3e352ee16a304427bdfe5178bd4c9471.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '95d1594e329a450583d3dc489f14b0c1', 'https://media.liche.cn/meijiaka-zy/materials/95d1594e329a450583d3dc489f14b0c1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), '9af7e719314049eaafb324a2305f55ad', 'https://media.liche.cn/meijiaka-zy/materials/9af7e719314049eaafb324a2305f55ad.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '99d03fef91774a7989f96345aead7a17', 'https://media.liche.cn/meijiaka-zy/materials/99d03fef91774a7989f96345aead7a17.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '03884e255c764f50a54321e724f454f7', 'https://media.liche.cn/meijiaka-zy/materials/03884e255c764f50a54321e724f454f7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), 'f5b120530577421c90fef3bf6cccd148', 'https://media.liche.cn/meijiaka-zy/materials/f5b120530577421c90fef3bf6cccd148.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), 'e8a55ba973ac4818a9ffb8d40862ab6d', 'https://media.liche.cn/meijiaka-zy/materials/e8a55ba973ac4818a9ffb8d40862ab6d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要猫眼' AND level = 3), '679c4e8fc17f4008b3ec23502c80a446', 'https://media.liche.cn/meijiaka-zy/materials/679c4e8fc17f4008b3ec23502c80a446.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '41a9ef200d5240888f39859afc43c445', 'https://media.liche.cn/meijiaka-zy/materials/41a9ef200d5240888f39859afc43c445.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '26951aa9816d4966a3cc1fb7e6664a35', 'https://media.liche.cn/meijiaka-zy/materials/26951aa9816d4966a3cc1fb7e6664a35.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要高光衣柜门' AND level = 3), '10c00e1a41094d04bd3fc370cd5d8e00', 'https://media.liche.cn/meijiaka-zy/materials/10c00e1a41094d04bd3fc370cd5d8e00.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), 'd43083a4ee534eb585c1b7bcb8955f27', 'https://media.liche.cn/meijiaka-zy/materials/d43083a4ee534eb585c1b7bcb8955f27.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), 'd58e403b6c8b46ff829cdb858fdc116a', 'https://media.liche.cn/meijiaka-zy/materials/d58e403b6c8b46ff829cdb858fdc116a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), '118373ff6c184e5f853b5c4898a145c1', 'https://media.liche.cn/meijiaka-zy/materials/118373ff6c184e5f853b5c4898a145c1.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), '93a4f4b5fc7c4e83b03f372c39a72ee0', 'https://media.liche.cn/meijiaka-zy/materials/93a4f4b5fc7c4e83b03f372c39a72ee0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), '6309fede0d27487292641637d917c44e', 'https://media.liche.cn/meijiaka-zy/materials/6309fede0d27487292641637d917c44e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), 'c2917a2ef1754b439b72e2664f145b95', 'https://media.liche.cn/meijiaka-zy/materials/c2917a2ef1754b439b72e2664f145b95.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), 'e714a0c031914387b7c1c15b8c551327', 'https://media.liche.cn/meijiaka-zy/materials/e714a0c031914387b7c1c15b8c551327.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要洗烘一体' AND level = 3), '0c5deba7591f4052a6995472aecf4fcc', 'https://media.liche.cn/meijiaka-zy/materials/0c5deba7591f4052a6995472aecf4fcc.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), 'a61431e53ff045fcbc907b65ca7851e5', 'https://media.liche.cn/meijiaka-zy/materials/a61431e53ff045fcbc907b65ca7851e5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), '09ac81d120864c518d1f2b803f44b52d', 'https://media.liche.cn/meijiaka-zy/materials/09ac81d120864c518d1f2b803f44b52d.mp4', 5.57, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), 'a493a81671474d7180921330656b1ea5', 'https://media.liche.cn/meijiaka-zy/materials/a493a81671474d7180921330656b1ea5.mp4', 6.8, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), '98b7149f57724c39927c2166ddddab46', 'https://media.liche.cn/meijiaka-zy/materials/98b7149f57724c39927c2166ddddab46.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), 'ef00983e89af4b24b8c46e9de5216cd3', 'https://media.liche.cn/meijiaka-zy/materials/ef00983e89af4b24b8c46e9de5216cd3.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), '96357bdcf9ba47cfb80f34596ee56d4d', 'https://media.liche.cn/meijiaka-zy/materials/96357bdcf9ba47cfb80f34596ee56d4d.mp4', 9.93, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), '6403394319d64c3c9f27504fbdf4df39', 'https://media.liche.cn/meijiaka-zy/materials/6403394319d64c3c9f27504fbdf4df39.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), '205edab436d246d1b45fb144a5d51376', 'https://media.liche.cn/meijiaka-zy/materials/205edab436d246d1b45fb144a5d51376.mp4', 6.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), '7bd1797f354a45778bd631caa6c64ede', 'https://media.liche.cn/meijiaka-zy/materials/7bd1797f354a45778bd631caa6c64ede.mp4', 8.63, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), '27f8b338680045a8958002d85776cb4c', 'https://media.liche.cn/meijiaka-zy/materials/27f8b338680045a8958002d85776cb4c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要虹吸马桶' AND level = 3), '00bf2c74715646cca752757efc10beec', 'https://media.liche.cn/meijiaka-zy/materials/00bf2c74715646cca752757efc10beec.mp4', 7.53, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), '930753a2127240bf8c7f80aef6c9dc56', 'https://media.liche.cn/meijiaka-zy/materials/930753a2127240bf8c7f80aef6c9dc56.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要贵妃椅沙发' AND level = 3), '983061eb541541b798dcc41b37034a8d', 'https://media.liche.cn/meijiaka-zy/materials/983061eb541541b798dcc41b37034a8d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), '765dbaa0a84841829075d8d213c4b78f', 'https://media.liche.cn/meijiaka-zy/materials/765dbaa0a84841829075d8d213c4b78f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), 'f972771193bd435bbf0584b1fea9b97d', 'https://media.liche.cn/meijiaka-zy/materials/f972771193bd435bbf0584b1fea9b97d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), 'f71e5df6388541e4988aebc0be158a18', 'https://media.liche.cn/meijiaka-zy/materials/f71e5df6388541e4988aebc0be158a18.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), '803cdb7478ef45ef86ec56eb46b9345d', 'https://media.liche.cn/meijiaka-zy/materials/803cdb7478ef45ef86ec56eb46b9345d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), '533ba271f62c4e8aa4a3cb118a5689d1', 'https://media.liche.cn/meijiaka-zy/materials/533ba271f62c4e8aa4a3cb118a5689d1.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), 'f29e276e2e1c42b99bffa96032854094', 'https://media.liche.cn/meijiaka-zy/materials/f29e276e2e1c42b99bffa96032854094.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要隐形衣架' AND level = 3), '17875ad8a2604152b358414011f0c52b', 'https://media.liche.cn/meijiaka-zy/materials/17875ad8a2604152b358414011f0c52b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要拼色窗帘' AND level = 3), 'be144a773dd94fa398b560164d14642f', 'https://media.liche.cn/meijiaka-zy/materials/be144a773dd94fa398b560164d14642f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要拼色窗帘' AND level = 3), '6177b805cd964905b950eeb104524659', 'https://media.liche.cn/meijiaka-zy/materials/6177b805cd964905b950eeb104524659.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地马桶' AND level = 3), '68b0cddcf0a04fc19d0782c9963c77e6', 'https://media.liche.cn/meijiaka-zy/materials/68b0cddcf0a04fc19d0782c9963c77e6.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要拼色窗帘' AND level = 3), '0f2bc77c05104d4ea0c11e25aa08115b', 'https://media.liche.cn/meijiaka-zy/materials/0f2bc77c05104d4ea0c11e25aa08115b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地马桶' AND level = 3), 'b7f3e47811ac41c0a30fda54168f7ed4', 'https://media.liche.cn/meijiaka-zy/materials/b7f3e47811ac41c0a30fda54168f7ed4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要拼色窗帘' AND level = 3), '249251617ca448ebacaf6975b9b71ae7', 'https://media.liche.cn/meijiaka-zy/materials/249251617ca448ebacaf6975b9b71ae7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地马桶' AND level = 3), 'd0925bb07fb74f0888c95561b2ab566a', 'https://media.liche.cn/meijiaka-zy/materials/d0925bb07fb74f0888c95561b2ab566a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地马桶' AND level = 3), 'fe5119cdb10741678588a1d69b5d63cd', 'https://media.liche.cn/meijiaka-zy/materials/fe5119cdb10741678588a1d69b5d63cd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要拼色窗帘' AND level = 3), '65a0707002a84f61b15385f45ec2375f', 'https://media.liche.cn/meijiaka-zy/materials/65a0707002a84f61b15385f45ec2375f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), '0b6e55fe249448d085bf9fd800fcafc2', 'https://media.liche.cn/meijiaka-zy/materials/0b6e55fe249448d085bf9fd800fcafc2.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), '812893cff85d4e848939cbc02f4d3a52', 'https://media.liche.cn/meijiaka-zy/materials/812893cff85d4e848939cbc02f4d3a52.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要落地马桶' AND level = 3), '500b0823454e4e3f89c5d6b95a4d53d4', 'https://media.liche.cn/meijiaka-zy/materials/500b0823454e4e3f89c5d6b95a4d53d4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), '06aa391dd23d46d4ba0c2e1632fa347e', 'https://media.liche.cn/meijiaka-zy/materials/06aa391dd23d46d4ba0c2e1632fa347e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), 'db3a49590c5443cdb981cfe307787fd4', 'https://media.liche.cn/meijiaka-zy/materials/db3a49590c5443cdb981cfe307787fd4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), '6a3f1ddff0334dc68c1503ef39597d10', 'https://media.liche.cn/meijiaka-zy/materials/6a3f1ddff0334dc68c1503ef39597d10.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), 'a2a0996c728f4b3aa641f03ab50aac17', 'https://media.liche.cn/meijiaka-zy/materials/a2a0996c728f4b3aa641f03ab50aac17.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要全屋WiFi' AND level = 3), 'b5e5ff9f175d4dc3bbab9185961d0b29', 'https://media.liche.cn/meijiaka-zy/materials/b5e5ff9f175d4dc3bbab9185961d0b29.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), '1eb1aa766cf04302a802b5269b7d737b', 'https://media.liche.cn/meijiaka-zy/materials/1eb1aa766cf04302a802b5269b7d737b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), 'f37971d4da0f478fa3f65d172188fe25', 'https://media.liche.cn/meijiaka-zy/materials/f37971d4da0f478fa3f65d172188fe25.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), '977ee163c78e4f11847ace2047c56d34', 'https://media.liche.cn/meijiaka-zy/materials/977ee163c78e4f11847ace2047c56d34.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), '77eb5c3ce66243cdabb6f7ed18f29202', 'https://media.liche.cn/meijiaka-zy/materials/77eb5c3ce66243cdabb6f7ed18f29202.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), '65cc19cd5fc64d3f84e10db738995d30', 'https://media.liche.cn/meijiaka-zy/materials/65cc19cd5fc64d3f84e10db738995d30.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要普通床' AND level = 3), '775387dc2e5942ad889f6c76e2948f45', 'https://media.liche.cn/meijiaka-zy/materials/775387dc2e5942ad889f6c76e2948f45.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), 'f36462b02b9f42679040a137e6691f52', 'https://media.liche.cn/meijiaka-zy/materials/f36462b02b9f42679040a137e6691f52.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), '40c299207cf247ee95696781e9dfdc05', 'https://media.liche.cn/meijiaka-zy/materials/40c299207cf247ee95696781e9dfdc05.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '892c4b8e42e0452e8e6ae49ac0ca7a69', 'https://media.liche.cn/meijiaka-zy/materials/892c4b8e42e0452e8e6ae49ac0ca7a69.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '32bf3247e6274e7cb7bf7e1a908f3088', 'https://media.liche.cn/meijiaka-zy/materials/32bf3247e6274e7cb7bf7e1a908f3088.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), 'aa04060ba6c941b29fc22728668caf5e', 'https://media.liche.cn/meijiaka-zy/materials/aa04060ba6c941b29fc22728668caf5e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), 'e65de6a8f27f4025a8f5580c7988da1f', 'https://media.liche.cn/meijiaka-zy/materials/e65de6a8f27f4025a8f5580c7988da1f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), '361f896730d2457c8007c0927676cfce', 'https://media.liche.cn/meijiaka-zy/materials/361f896730d2457c8007c0927676cfce.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要直排沙发' AND level = 3), '428414da7ecb423fa0b37894222ebb8f', 'https://media.liche.cn/meijiaka-zy/materials/428414da7ecb423fa0b37894222ebb8f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '5d15d7e490c140daa8127d00095d7375', 'https://media.liche.cn/meijiaka-zy/materials/5d15d7e490c140daa8127d00095d7375.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), 'a584815812ce414ebb489531fa9b7c16', 'https://media.liche.cn/meijiaka-zy/materials/a584815812ce414ebb489531fa9b7c16.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '1287d724a14e40a7846bcdd8aaffa172', 'https://media.liche.cn/meijiaka-zy/materials/1287d724a14e40a7846bcdd8aaffa172.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), 'ef24862d3cbe48fbaec7ac096eb339dd', 'https://media.liche.cn/meijiaka-zy/materials/ef24862d3cbe48fbaec7ac096eb339dd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), 'e0a62b1204f4453c90ad0bae9d363adb', 'https://media.liche.cn/meijiaka-zy/materials/e0a62b1204f4453c90ad0bae9d363adb.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), '4f253300cc2242aa93f672c47871c4a8', 'https://media.liche.cn/meijiaka-zy/materials/4f253300cc2242aa93f672c47871c4a8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '357979b0e74346bca50e6449b8011889', 'https://media.liche.cn/meijiaka-zy/materials/357979b0e74346bca50e6449b8011889.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要悬浮电视柜' AND level = 3), '94d47460990341ec93d9d7180cd00b9e', 'https://media.liche.cn/meijiaka-zy/materials/94d47460990341ec93d9d7180cd00b9e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), '4c2ab0da72e14bc0a4732a4b06091270', 'https://media.liche.cn/meijiaka-zy/materials/4c2ab0da72e14bc0a4732a4b06091270.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), '289c4f7f4de54f96af16ea0c22dd561b', 'https://media.liche.cn/meijiaka-zy/materials/289c4f7f4de54f96af16ea0c22dd561b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), '07eeced430644d029e58b9d7bddd46a7', 'https://media.liche.cn/meijiaka-zy/materials/07eeced430644d029e58b9d7bddd46a7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), '160cfb8fb1b549f39a287fccea8fc8ed', 'https://media.liche.cn/meijiaka-zy/materials/160cfb8fb1b549f39a287fccea8fc8ed.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要罗马杠' AND level = 3), 'f2855c4731cf4d30814d88eac44da9d0', 'https://media.liche.cn/meijiaka-zy/materials/f2855c4731cf4d30814d88eac44da9d0.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), 'aebc1fe3db2b4b95824c5831ea812bd3', 'https://media.liche.cn/meijiaka-zy/materials/aebc1fe3db2b4b95824c5831ea812bd3.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), '91176da1353c48f79b52f2b8abf8d94f', 'https://media.liche.cn/meijiaka-zy/materials/91176da1353c48f79b52f2b8abf8d94f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), '1120cef1ba9f42a6829ce7e09d673e07', 'https://media.liche.cn/meijiaka-zy/materials/1120cef1ba9f42a6829ce7e09d673e07.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), 'd66cdc8993e54e81be018eb3f86c64ac', 'https://media.liche.cn/meijiaka-zy/materials/d66cdc8993e54e81be018eb3f86c64ac.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'b2e844cdf81c4d5784aa4f962016f523', 'https://media.liche.cn/meijiaka-zy/materials/b2e844cdf81c4d5784aa4f962016f523.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '5a265500b1604baeb96b2259a1cf9b0a', 'https://media.liche.cn/meijiaka-zy/materials/5a265500b1604baeb96b2259a1cf9b0a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要小双槽' AND level = 3), '51a95971572741f4909e35c4e71b5264', 'https://media.liche.cn/meijiaka-zy/materials/51a95971572741f4909e35c4e71b5264.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'd9b0de35c46f467297be8ce3a2a16458', 'https://media.liche.cn/meijiaka-zy/materials/d9b0de35c46f467297be8ce3a2a16458.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '9cea19a9a9a34594b2fd77f9b92dde8e', 'https://media.liche.cn/meijiaka-zy/materials/9cea19a9a9a34594b2fd77f9b92dde8e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要直排下水' AND level = 3), '6be1e0f6ca94401f89581b146c89b678', 'https://media.liche.cn/meijiaka-zy/materials/6be1e0f6ca94401f89581b146c89b678.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '352da1f235e5482db0a4be978eff93f6', 'https://media.liche.cn/meijiaka-zy/materials/352da1f235e5482db0a4be978eff93f6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要小双槽' AND level = 3), 'a1a7ab30595048eda9aa225a715f17de', 'https://media.liche.cn/meijiaka-zy/materials/a1a7ab30595048eda9aa225a715f17de.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '1e8ae6f922c74ee49dc2d2e04533b22b', 'https://media.liche.cn/meijiaka-zy/materials/1e8ae6f922c74ee49dc2d2e04533b22b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要小双槽' AND level = 3), '941c49766cde43878f8c8da19d17456e', 'https://media.liche.cn/meijiaka-zy/materials/941c49766cde43878f8c8da19d17456e.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要小双槽' AND level = 3), '849c553dbc9647479685ef83cf1100be', 'https://media.liche.cn/meijiaka-zy/materials/849c553dbc9647479685ef83cf1100be.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '21bd4978aeaa4d159d1800db2b984082', 'https://media.liche.cn/meijiaka-zy/materials/21bd4978aeaa4d159d1800db2b984082.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'b258f7e0056f4baeb6eebd7240f76d2f', 'https://media.liche.cn/meijiaka-zy/materials/b258f7e0056f4baeb6eebd7240f76d2f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'e2d0a9cf56704443806658ea940713c2', 'https://media.liche.cn/meijiaka-zy/materials/e2d0a9cf56704443806658ea940713c2.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要小双槽' AND level = 3), '15e2a3fc0be5410bb358e00ed631a12a', 'https://media.liche.cn/meijiaka-zy/materials/15e2a3fc0be5410bb358e00ed631a12a.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '30e0a3c7691846489dee768eddef4a0f', 'https://media.liche.cn/meijiaka-zy/materials/30e0a3c7691846489dee768eddef4a0f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'efa8f5fd74784a7a8495361e5b99b1f7', 'https://media.liche.cn/meijiaka-zy/materials/efa8f5fd74784a7a8495361e5b99b1f7.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '4173780f85b942ad86f5b486af7c011d', 'https://media.liche.cn/meijiaka-zy/materials/4173780f85b942ad86f5b486af7c011d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '2285017783074568b4d5bc8a1461ec1d', 'https://media.liche.cn/meijiaka-zy/materials/2285017783074568b4d5bc8a1461ec1d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), '34bd7f3c37b146e1a476938ea403d055', 'https://media.liche.cn/meijiaka-zy/materials/34bd7f3c37b146e1a476938ea403d055.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要插座外露' AND level = 3), 'ef33cfa03f6d484ab2c6fcdaed3a16a5', 'https://media.liche.cn/meijiaka-zy/materials/ef33cfa03f6d484ab2c6fcdaed3a16a5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要浅色地砖' AND level = 3), '33c4d254299f431a9e191169b7202628', 'https://media.liche.cn/meijiaka-zy/materials/33c4d254299f431a9e191169b7202628.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要浅色地砖' AND level = 3), '8014ecc06ee44df1941ed4d8375b6fb8', 'https://media.liche.cn/meijiaka-zy/materials/8014ecc06ee44df1941ed4d8375b6fb8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要浅色地砖' AND level = 3), '00391f1a737c42a7b9b5347aeedff97c', 'https://media.liche.cn/meijiaka-zy/materials/00391f1a737c42a7b9b5347aeedff97c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要浅色地砖' AND level = 3), '7a0146956eee48899896e65c6eafeef8', 'https://media.liche.cn/meijiaka-zy/materials/7a0146956eee48899896e65c6eafeef8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要正五孔插座' AND level = 3), 'dfca6efd3d74403682b02a0e0eb8fdf4', 'https://media.liche.cn/meijiaka-zy/materials/dfca6efd3d74403682b02a0e0eb8fdf4.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要深色地砖' AND level = 3), '1c470f318ef146219530880d3ce84e11', 'https://media.liche.cn/meijiaka-zy/materials/1c470f318ef146219530880d3ce84e11.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要浅色地砖' AND level = 3), 'e104a916748e4049bd7179d70860de88', 'https://media.liche.cn/meijiaka-zy/materials/e104a916748e4049bd7179d70860de88.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要深色地砖' AND level = 3), 'ed6110e2cc6d4e10b9c7dbaa4cb4ea00', 'https://media.liche.cn/meijiaka-zy/materials/ed6110e2cc6d4e10b9c7dbaa4cb4ea00.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要深色地砖' AND level = 3), '42462509e9254b01a460110e739152bf', 'https://media.liche.cn/meijiaka-zy/materials/42462509e9254b01a460110e739152bf.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要深色地砖' AND level = 3), 'cc38a470493845309c23ecee9e21ca5f', 'https://media.liche.cn/meijiaka-zy/materials/cc38a470493845309c23ecee9e21ca5f.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要深色地砖' AND level = 3), 'dacb0053c4ff461c992df523d65daa53', 'https://media.liche.cn/meijiaka-zy/materials/dacb0053c4ff461c992df523d65daa53.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要正五孔插座' AND level = 3), '87ae58824aba4ecab5a946d8105a0635', 'https://media.liche.cn/meijiaka-zy/materials/87ae58824aba4ecab5a946d8105a0635.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要正五孔插座' AND level = 3), 'bd1e9299fbd545d58322f48f6ec0e101', 'https://media.liche.cn/meijiaka-zy/materials/bd1e9299fbd545d58322f48f6ec0e101.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要正五孔插座' AND level = 3), 'e5fc20263c134b56a65ab5056993a02d', 'https://media.liche.cn/meijiaka-zy/materials/e5fc20263c134b56a65ab5056993a02d.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要正五孔插座' AND level = 3), '5adf7928450b4b07acdf80f1bcd0ea81', 'https://media.liche.cn/meijiaka-zy/materials/5adf7928450b4b07acdf80f1bcd0ea81.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'fa27b60fcbd94e76b3011eaf2ca7907b', 'https://media.liche.cn/meijiaka-zy/materials/fa27b60fcbd94e76b3011eaf2ca7907b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'e55116f21a9a415b885eae6d00035c54', 'https://media.liche.cn/meijiaka-zy/materials/e55116f21a9a415b885eae6d00035c54.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'a022570f0a0448459bb315fb9dd43ab1', 'https://media.liche.cn/meijiaka-zy/materials/a022570f0a0448459bb315fb9dd43ab1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '6eeab030d87a4688ad18dccfba371c29', 'https://media.liche.cn/meijiaka-zy/materials/6eeab030d87a4688ad18dccfba371c29.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'f0aeb34fb07d4a63a24d4eaafdc45ef9', 'https://media.liche.cn/meijiaka-zy/materials/f0aeb34fb07d4a63a24d4eaafdc45ef9.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'ee743900e34040dab9c22c3a2d6aac0f', 'https://media.liche.cn/meijiaka-zy/materials/ee743900e34040dab9c22c3a2d6aac0f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '35c15d3f52b447609bd28653969fa1d6', 'https://media.liche.cn/meijiaka-zy/materials/35c15d3f52b447609bd28653969fa1d6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '97032eed200e4d9aaadc325965af9162', 'https://media.liche.cn/meijiaka-zy/materials/97032eed200e4d9aaadc325965af9162.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'ec84f683dade42779a09ea7f3669aaa5', 'https://media.liche.cn/meijiaka-zy/materials/ec84f683dade42779a09ea7f3669aaa5.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'de049d7f63694dd78c935e295f91eb13', 'https://media.liche.cn/meijiaka-zy/materials/de049d7f63694dd78c935e295f91eb13.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), '766811950b2a435fb3bc7d4bc298d87b', 'https://media.liche.cn/meijiaka-zy/materials/766811950b2a435fb3bc7d4bc298d87b.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'c88a72bb2da744bb9303e172d820fc30', 'https://media.liche.cn/meijiaka-zy/materials/c88a72bb2da744bb9303e172d820fc30.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要窗帘盒' AND level = 3), 'c81a5df9f1ea481cac67fd9b2e61c7dd', 'https://media.liche.cn/meijiaka-zy/materials/c81a5df9f1ea481cac67fd9b2e61c7dd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'cfd980a9e6484f4d93733e28098fe72a', 'https://media.liche.cn/meijiaka-zy/materials/cfd980a9e6484f4d93733e28098fe72a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '31388e41a091422bbf8f5a0efb5d2566', 'https://media.liche.cn/meijiaka-zy/materials/31388e41a091422bbf8f5a0efb5d2566.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'f11a882a9cea44488c2f6507b5aa4ca1', 'https://media.liche.cn/meijiaka-zy/materials/f11a882a9cea44488c2f6507b5aa4ca1.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'b56bf8a89af1406aa68bfc4d9cb62891', 'https://media.liche.cn/meijiaka-zy/materials/b56bf8a89af1406aa68bfc4d9cb62891.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '6de018842041425ab9c82da8d3a3720a', 'https://media.liche.cn/meijiaka-zy/materials/6de018842041425ab9c82da8d3a3720a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '65397b0f281a4e31a47fe95470f4ea10', 'https://media.liche.cn/meijiaka-zy/materials/65397b0f281a4e31a47fe95470f4ea10.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'a07cfdee6d584e5b8a2f72661e1ee86a', 'https://media.liche.cn/meijiaka-zy/materials/a07cfdee6d584e5b8a2f72661e1ee86a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'de94d5432a254286bf0768cba518f286', 'https://media.liche.cn/meijiaka-zy/materials/de94d5432a254286bf0768cba518f286.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'd7a2a2d231cd480aae8548aad5c804e0', 'https://media.liche.cn/meijiaka-zy/materials/d7a2a2d231cd480aae8548aad5c804e0.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '3f8f27ac22324651bb05caa9d5f47c0a', 'https://media.liche.cn/meijiaka-zy/materials/3f8f27ac22324651bb05caa9d5f47c0a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'b8a4f3c222584922a8455c88fb7b3378', 'https://media.liche.cn/meijiaka-zy/materials/b8a4f3c222584922a8455c88fb7b3378.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '17b98ac5b0e24f9fa6adaf574b8f828c', 'https://media.liche.cn/meijiaka-zy/materials/17b98ac5b0e24f9fa6adaf574b8f828c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '0becb3ceabd9434d9cf968131cd8c586', 'https://media.liche.cn/meijiaka-zy/materials/0becb3ceabd9434d9cf968131cd8c586.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '851bb0e730ba46f484e265882ae269b5', 'https://media.liche.cn/meijiaka-zy/materials/851bb0e730ba46f484e265882ae269b5.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '9950534f4f6649399d86762993efb7d6', 'https://media.liche.cn/meijiaka-zy/materials/9950534f4f6649399d86762993efb7d6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'fac9f5e081e74a3aa59a9d0aa281923d', 'https://media.liche.cn/meijiaka-zy/materials/fac9f5e081e74a3aa59a9d0aa281923d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), '6283199e7ff2415d8c6f149460c29e03', 'https://media.liche.cn/meijiaka-zy/materials/6283199e7ff2415d8c6f149460c29e03.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'eefd84d3897b49aebe4167693d4cb827', 'https://media.liche.cn/meijiaka-zy/materials/eefd84d3897b49aebe4167693d4cb827.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'a9dde443bb1843fdb54b1fa484b4848a', 'https://media.liche.cn/meijiaka-zy/materials/a9dde443bb1843fdb54b1fa484b4848a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '不要造型柜门' AND level = 3), 'eb46f648f7d647a5bd21f0ce90f28022', 'https://media.liche.cn/meijiaka-zy/materials/eb46f648f7d647a5bd21f0ce90f28022.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'b7180ebc50a6423f98be4f401440196f', 'https://media.liche.cn/meijiaka-zy/materials/b7180ebc50a6423f98be4f401440196f.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'a37352b64a7b46d68aef4191d8fd0027', 'https://media.liche.cn/meijiaka-zy/materials/a37352b64a7b46d68aef4191d8fd0027.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '5436a7773c234f3487dc7a475ac24213', 'https://media.liche.cn/meijiaka-zy/materials/5436a7773c234f3487dc7a475ac24213.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '57018b970ff94dcbb3b063aed81e2b18', 'https://media.liche.cn/meijiaka-zy/materials/57018b970ff94dcbb3b063aed81e2b18.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '1651f748efb54841b725de0a4fcd70c8', 'https://media.liche.cn/meijiaka-zy/materials/1651f748efb54841b725de0a4fcd70c8.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '1702d4905ae144d7bebd00a61e992f3d', 'https://media.liche.cn/meijiaka-zy/materials/1702d4905ae144d7bebd00a61e992f3d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '4a94ef26cc824bf9a48c2c73d651f243', 'https://media.liche.cn/meijiaka-zy/materials/4a94ef26cc824bf9a48c2c73d651f243.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'b6e3e5079ad24cbeb12bff86a0a19c01', 'https://media.liche.cn/meijiaka-zy/materials/b6e3e5079ad24cbeb12bff86a0a19c01.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '5396cda8a34348d2bb295995eccb3d31', 'https://media.liche.cn/meijiaka-zy/materials/5396cda8a34348d2bb295995eccb3d31.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'd1706a826e2546acbf8a270a4056aabd', 'https://media.liche.cn/meijiaka-zy/materials/d1706a826e2546acbf8a270a4056aabd.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), 'cf63971d5341429cab4f35c046b5586c', 'https://media.liche.cn/meijiaka-zy/materials/cf63971d5341429cab4f35c046b5586c.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '6f2acadce9aa455da59bf6ec9b35b4cd', 'https://media.liche.cn/meijiaka-zy/materials/6f2acadce9aa455da59bf6ec9b35b4cd.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '533db42e486e492086dcf33a46e92a93', 'https://media.liche.cn/meijiaka-zy/materials/533db42e486e492086dcf33a46e92a93.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '4601fdeaeec34e5e8b0febe988ff8082', 'https://media.liche.cn/meijiaka-zy/materials/4601fdeaeec34e5e8b0febe988ff8082.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'adc727c9c2e84b77acca89a5394b1ae3', 'https://media.liche.cn/meijiaka-zy/materials/adc727c9c2e84b77acca89a5394b1ae3.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '2bf44e2abdb349939963d53d6834ae8e', 'https://media.liche.cn/meijiaka-zy/materials/2bf44e2abdb349939963d53d6834ae8e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'c8023d0105e84540aea50c1434d1b5e9', 'https://media.liche.cn/meijiaka-zy/materials/c8023d0105e84540aea50c1434d1b5e9.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'dcdce38c6c944a09b228102e958b0e50', 'https://media.liche.cn/meijiaka-zy/materials/dcdce38c6c944a09b228102e958b0e50.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要干湿分离卫生间' AND level = 3), '5bdcd0442c574435b0858195044caab7', 'https://media.liche.cn/meijiaka-zy/materials/5bdcd0442c574435b0858195044caab7.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '52e13dd959e347bc95e26214854122ff', 'https://media.liche.cn/meijiaka-zy/materials/52e13dd959e347bc95e26214854122ff.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '4fd0a1603d864c88ae5b716e50adaf2b', 'https://media.liche.cn/meijiaka-zy/materials/4fd0a1603d864c88ae5b716e50adaf2b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'a48e2f2103df4905890acb3f0d9dad4d', 'https://media.liche.cn/meijiaka-zy/materials/a48e2f2103df4905890acb3f0d9dad4d.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '293096bce2874c30af1857953871799e', 'https://media.liche.cn/meijiaka-zy/materials/293096bce2874c30af1857953871799e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '3e9aba5322324c0e870fd922fd6679d6', 'https://media.liche.cn/meijiaka-zy/materials/3e9aba5322324c0e870fd922fd6679d6.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '073cb07ba3114140982049cdc661a80e', 'https://media.liche.cn/meijiaka-zy/materials/073cb07ba3114140982049cdc661a80e.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '0ba64331277642f8b7b22dcde5a25047', 'https://media.liche.cn/meijiaka-zy/materials/0ba64331277642f8b7b22dcde5a25047.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '724cc0731286407198faf8d496bf45bf', 'https://media.liche.cn/meijiaka-zy/materials/724cc0731286407198faf8d496bf45bf.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '96d1850794aa4c4bbc5e0f02bdef8856', 'https://media.liche.cn/meijiaka-zy/materials/96d1850794aa4c4bbc5e0f02bdef8856.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'b8600fef424740a4adc8e31306f35d24', 'https://media.liche.cn/meijiaka-zy/materials/b8600fef424740a4adc8e31306f35d24.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '6d4d03b893454441b0ae6cebc1182c83', 'https://media.liche.cn/meijiaka-zy/materials/6d4d03b893454441b0ae6cebc1182c83.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'cd67779075df422ea4d6e11f0c9ba385', 'https://media.liche.cn/meijiaka-zy/materials/cd67779075df422ea4d6e11f0c9ba385.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '7e1e6f3f32f543e69f51ceb7b19c9c7c', 'https://media.liche.cn/meijiaka-zy/materials/7e1e6f3f32f543e69f51ceb7b19c9c7c.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'e7760d522ca94753a80a632149f6b63a', 'https://media.liche.cn/meijiaka-zy/materials/e7760d522ca94753a80a632149f6b63a.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), '794dab7964fc4c3b9b9efa1d2292a79b', 'https://media.liche.cn/meijiaka-zy/materials/794dab7964fc4c3b9b9efa1d2292a79b.mp4', 3.02, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '要平板柜门' AND level = 3), 'afe76dc6bc1f49d18af041b174e18446', 'https://media.liche.cn/meijiaka-zy/materials/afe76dc6bc1f49d18af041b174e18446.mp4', 3.02, 0, 'active', NOW(), NOW()); diff --git a/scripts/insert_cover_backgrounds_bk.sql b/scripts/insert_cover_backgrounds_bk.sql deleted file mode 100644 index 3c8e96a..0000000 --- a/scripts/insert_cover_backgrounds_bk.sql +++ /dev/null @@ -1,47 +0,0 @@ --- 封面背景图批量导入 SQL --- script_code: bk(装修避坑) --- 生成时间: 2026-06-01 --- 共 41 张 - -INSERT INTO mjk_cover_backgrounds (script_code, title, url, sort_order, status, created_at, updated_at) VALUES - ('bk', '04e1bd3b19', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/04e1bd3b19.png', 1, 'active', NOW(), NOW()) -, ('bk', '1c7d6b9ce9', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/1c7d6b9ce9.png', 2, 'active', NOW(), NOW()) -, ('bk', '2508cc7679', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/2508cc7679.png', 3, 'active', NOW(), NOW()) -, ('bk', '280bc39306', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/280bc39306.png', 4, 'active', NOW(), NOW()) -, ('bk', '2bb52b3f65', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/2bb52b3f65.png', 5, 'active', NOW(), NOW()) -, ('bk', '2c08dbd929', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/2c08dbd929.png', 6, 'active', NOW(), NOW()) -, ('bk', '3079192f62', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/3079192f62.png', 7, 'active', NOW(), NOW()) -, ('bk', '3409a04e66', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/3409a04e66.png', 8, 'active', NOW(), NOW()) -, ('bk', '3cd57f9008', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/3cd57f9008.png', 9, 'active', NOW(), NOW()) -, ('bk', '4a7555e3f0', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/4a7555e3f0.png', 10, 'active', NOW(), NOW()) -, ('bk', '4c3965959a', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/4c3965959a.png', 11, 'active', NOW(), NOW()) -, ('bk', '4cecdd5f83', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/4cecdd5f83.png', 12, 'active', NOW(), NOW()) -, ('bk', '54b164fef1', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/54b164fef1.png', 13, 'active', NOW(), NOW()) -, ('bk', '5fd98a1da7', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/5fd98a1da7.png', 14, 'active', NOW(), NOW()) -, ('bk', '645f2970bf', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/645f2970bf.png', 15, 'active', NOW(), NOW()) -, ('bk', '70cb74ee0e', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/70cb74ee0e.png', 16, 'active', NOW(), NOW()) -, ('bk', '76955a5f76', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/76955a5f76.png', 17, 'active', NOW(), NOW()) -, ('bk', '8395b3784a', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/8395b3784a.png', 18, 'active', NOW(), NOW()) -, ('bk', '85c6ed85e1', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/85c6ed85e1.png', 19, 'active', NOW(), NOW()) -, ('bk', '95ff4cf029', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/95ff4cf029.png', 20, 'active', NOW(), NOW()) -, ('bk', '979dfb0215', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/979dfb0215.png', 21, 'active', NOW(), NOW()) -, ('bk', 'a12d375624', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/a12d375624.png', 22, 'active', NOW(), NOW()) -, ('bk', 'a1411511aa', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/a1411511aa.png', 23, 'active', NOW(), NOW()) -, ('bk', 'a16a0b348c', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/a16a0b348c.png', 24, 'active', NOW(), NOW()) -, ('bk', 'ae4ed9a335', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/ae4ed9a335.png', 25, 'active', NOW(), NOW()) -, ('bk', 'c07f6556fd', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/c07f6556fd.png', 26, 'active', NOW(), NOW()) -, ('bk', 'c1460b5f5a', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/c1460b5f5a.png', 27, 'active', NOW(), NOW()) -, ('bk', 'cd8b455000', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/cd8b455000.png', 28, 'active', NOW(), NOW()) -, ('bk', 'd16d93b73d', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/d16d93b73d.png', 29, 'active', NOW(), NOW()) -, ('bk', 'd18088bb3f', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/d18088bb3f.png', 30, 'active', NOW(), NOW()) -, ('bk', 'd540fc6c4b', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/d540fc6c4b.png', 31, 'active', NOW(), NOW()) -, ('bk', 'dbf4c4ff92', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/dbf4c4ff92.png', 32, 'active', NOW(), NOW()) -, ('bk', 'dce3d6fb91', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/dce3d6fb91.png', 33, 'active', NOW(), NOW()) -, ('bk', 'ec8c953ccb', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/ec8c953ccb.png', 34, 'active', NOW(), NOW()) -, ('bk', 'ef9575b715', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/ef9575b715.png', 35, 'active', NOW(), NOW()) -, ('bk', 'f3023c5554', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/f3023c5554.png', 36, 'active', NOW(), NOW()) -, ('bk', 'f4679775ce', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/f4679775ce.png', 37, 'active', NOW(), NOW()) -, ('bk', 'f9192aa4a9', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/f9192aa4a9.png', 38, 'active', NOW(), NOW()) -, ('bk', 'f98d79311e', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/f98d79311e.png', 39, 'active', NOW(), NOW()) -, ('bk', 'fadcca7a06', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/fadcca7a06.png', 40, 'active', NOW(), NOW()) -, ('bk', 'fb04e41a2c', 'https://img.liche.cn/meijiaka-zy/cover_templete/bk/fb04e41a2c.png', 41, 'active', NOW(), NOW()); diff --git a/scripts/insert_new_materials_6.2.sql b/scripts/insert_new_materials_6.2.sql deleted file mode 100644 index 7dfe986..0000000 --- a/scripts/insert_new_materials_6.2.sql +++ /dev/null @@ -1,72 +0,0 @@ --- 新增素材6.2 批量导入 SQL --- 共 67 个素材 --- URL前缀: https://media.liche.cn/meijiaka-zy/materials/ - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) VALUES - ((SELECT id FROM mjk_broll_categories WHERE name = '万华爱格兔宝宝' AND level = 3), '3c28619290414e552e988e09b3675b72', 'https://media.liche.cn/meijiaka-zy/materials/3c28619290414e552e988e09b3675b72.mp4', 5.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '东鹏冠珠马可波罗' AND level = 3), '182e4c8bbcea8f103672b147b4606213', 'https://media.liche.cn/meijiaka-zy/materials/182e4c8bbcea8f103672b147b4606213.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '九牧恒洁箭牌' AND level = 3), '7d5607ab1886ba948fc1e94398473274', 'https://media.liche.cn/meijiaka-zy/materials/7d5607ab1886ba948fc1e94398473274.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '九牧箭牌潜水艇' AND level = 3), '6924bfd00653c3c6cfcb2d1d02c4789c', 'https://media.liche.cn/meijiaka-zy/materials/6924bfd00653c3c6cfcb2d1d02c4789c.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '乳胶漆买谁家' AND level = 3), '6086a32ec41db26e5bc570f1f27c1fbc', 'https://media.liche.cn/meijiaka-zy/materials/6086a32ec41db26e5bc570f1f27c1fbc.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '公牛施耐德西门子' AND level = 3), 'c0a3e230b32026b78596c192718345cb', 'https://media.liche.cn/meijiaka-zy/materials/c0a3e230b32026b78596c192718345cb.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '冰箱买谁家' AND level = 3), 'fad1e564d3272515eab8dd75079870de', 'https://media.liche.cn/meijiaka-zy/materials/fad1e564d3272515eab8dd75079870de.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '厨卫五金谁家好' AND level = 3), '4d20e0593c973366e064451fd9561eff', 'https://media.liche.cn/meijiaka-zy/materials/4d20e0593c973366e064451fd9561eff.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '吊顶选谁家' AND level = 3), '4ee89978139e0e55c809aedf5a56ddc2', 'https://media.liche.cn/meijiaka-zy/materials/4ee89978139e0e55c809aedf5a56ddc2.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '圣象世友大自然' AND level = 3), '5c78732634c008867211a9a34d124881', 'https://media.liche.cn/meijiaka-zy/materials/5c78732634c008867211a9a34d124881.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '地板哪家好' AND level = 3), '647972fffa483aa807ecd08ed53219be', 'https://media.liche.cn/meijiaka-zy/materials/647972fffa483aa807ecd08ed53219be.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '地漏谁家好' AND level = 3), 'd4fb5c1a8bf3cecf8662f82b6977a954', 'https://media.liche.cn/meijiaka-zy/materials/d4fb5c1a8bf3cecf8662f82b6977a954.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '奥普友邦法狮龙' AND level = 3), 'a6cc0fb2a45ea0e4b988451baddac499', 'https://media.liche.cn/meijiaka-zy/materials/a6cc0fb2a45ea0e4b988451baddac499.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家装水泥谁家好' AND level = 3), 'e189e0507cd2ecb0be2e32d2cf65dccd', 'https://media.liche.cn/meijiaka-zy/materials/e189e0507cd2ecb0be2e32d2cf65dccd.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家装水管谁家好' AND level = 3), '72d9643978717084039cf3507f9bdd04', 'https://media.liche.cn/meijiaka-zy/materials/72d9643978717084039cf3507f9bdd04.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '开关插座买谁家' AND level = 3), '8df9cfec100cea2661784361571a3a11', 'https://media.liche.cn/meijiaka-zy/materials/8df9cfec100cea2661784361571a3a11.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '德高西卡马贝' AND level = 3), 'b365eb193c1ede5777cc04d2427ea0e7', 'https://media.liche.cn/meijiaka-zy/materials/b365eb193c1ede5777cc04d2427ea0e7.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '方太老板华帝' AND level = 3), '9e37037aad90b25493228d05c0405696', 'https://media.liche.cn/meijiaka-zy/materials/9e37037aad90b25493228d05c0405696.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '日丰伟星保利' AND level = 3), '3318c054d10f5ecca8ce397f435c01af', 'https://media.liche.cn/meijiaka-zy/materials/3318c054d10f5ecca8ce397f435c01af.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '板材选谁家' AND level = 3), '9e5eb608644425a51613e2e145ba28e0', 'https://media.liche.cn/meijiaka-zy/materials/9e5eb608644425a51613e2e145ba28e0.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '水管买谁家' AND level = 3), '0d37b9dbf4b44858f16f155ba88a7054', 'https://media.liche.cn/meijiaka-zy/materials/0d37b9dbf4b44858f16f155ba88a7054.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '海尔美的卡萨帝' AND level = 3), '33e3a3ae93f65e72d055431b0d132495', 'https://media.liche.cn/meijiaka-zy/materials/33e3a3ae93f65e72d055431b0d132495.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '海螺红狮中联' AND level = 3), 'cd7f119729a062df350940bb003f873d', 'https://media.liche.cn/meijiaka-zy/materials/cd7f119729a062df350940bb003f873d.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '烟机哪家好' AND level = 3), '01690f5d76a40142f365da61319c9f31', 'https://media.liche.cn/meijiaka-zy/materials/01690f5d76a40142f365da61319c9f31.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '玻璃胶谁家好' AND level = 3), '52d7c9db8291af1d9e2061c3288bec2b', 'https://media.liche.cn/meijiaka-zy/materials/52d7c9db8291af1d9e2061c3288bec2b.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓦克西卡百得' AND level = 3), '1e2774b366631016acecc03c322dc0a2', 'https://media.liche.cn/meijiaka-zy/materials/1e2774b366631016acecc03c322dc0a2.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖哪家好' AND level = 3), 'e727f0ea33030c14d33185329794398c', 'https://media.liche.cn/meijiaka-zy/materials/e727f0ea33030c14d33185329794398c.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '瓷砖胶谁家好' AND level = 3), '07a1f9a9ec09809d33781a2b6265ff48', 'https://media.liche.cn/meijiaka-zy/materials/07a1f9a9ec09809d33781a2b6265ff48.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电线买谁家' AND level = 3), '04f61f5a57454799d2aa1000764311af', 'https://media.liche.cn/meijiaka-zy/materials/04f61f5a57454799d2aa1000764311af.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '电视买谁家' AND level = 3), '82c400fbc27c42dd8992458d2e94c047', 'https://media.liche.cn/meijiaka-zy/materials/82c400fbc27c42dd8992458d2e94c047.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '石膏板谁家好' AND level = 3), 'e6469a2dc66350c330d2d87f08a9cd5a', 'https://media.liche.cn/meijiaka-zy/materials/e6469a2dc66350c330d2d87f08a9cd5a.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '科勒九牧汉斯格雅' AND level = 3), '80506a9eb5e1a06d3c5cb98eaae515cd', 'https://media.liche.cn/meijiaka-zy/materials/80506a9eb5e1a06d3c5cb98eaae515cd.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '立邦三棵树多乐士' AND level = 3), '82b26195cdb7a08793abf3ff17d400eb', 'https://media.liche.cn/meijiaka-zy/materials/82b26195cdb7a08793abf3ff17d400eb.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '立邦德高东方雨虹' AND level = 3), '03602a66190ad519f81c70a80e6cd0d2', 'https://media.liche.cn/meijiaka-zy/materials/03602a66190ad519f81c70a80e6cd0d2.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '立邦美巢圣戈邦' AND level = 3), 'cc00321964988a29315468e4dca53d06', 'https://media.liche.cn/meijiaka-zy/materials/cc00321964988a29315468e4dca53d06.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '索尼海信TCL' AND level = 3), 'fb9d3b062be7ed44fef7ec81490a4963', 'https://media.liche.cn/meijiaka-zy/materials/fb9d3b062be7ed44fef7ec81490a4963.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '腻子粉哪家好' AND level = 3), '887c5ea3238d2c1196eb09c410dc8f7f', 'https://media.liche.cn/meijiaka-zy/materials/887c5ea3238d2c1196eb09c410dc8f7f.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '花洒哪家好' AND level = 3), 'f6d4592e08482cb903daca04d432f3ed', 'https://media.liche.cn/meijiaka-zy/materials/f6d4592e08482cb903daca04d432f3ed.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '远东宝胜熊猫' AND level = 3), 'c5ac8d8ff5435e123c8016657fbf955c', 'https://media.liche.cn/meijiaka-zy/materials/c5ac8d8ff5435e123c8016657fbf955c.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '金牛伟星日丰' AND level = 3), '3c9546527a38c300050ed28bda81e204', 'https://media.liche.cn/meijiaka-zy/materials/3c9546527a38c300050ed28bda81e204.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '防水买谁家' AND level = 3), '3e7c5b554836376605828f374bd15ae5', 'https://media.liche.cn/meijiaka-zy/materials/3e7c5b554836376605828f374bd15ae5.mp4', 3.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '龙牌泰山可耐福' AND level = 3), '6589ffbf04c596583d2d2316216c7428', 'https://media.liche.cn/meijiaka-zy/materials/6589ffbf04c596583d2d2316216c7428.mp4', 5.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '488d5a9ac72bf8e9a2a574284f2bdded', 'https://media.liche.cn/meijiaka-zy/materials/488d5a9ac72bf8e9a2a574284f2bdded.mp4', 10.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '3c716b567964591569abfc8d16e7ff9b', 'https://media.liche.cn/meijiaka-zy/materials/3c716b567964591569abfc8d16e7ff9b.mp4', 9.97, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '2fb5183ef1547fb3d7d4d8e56fe5154a', 'https://media.liche.cn/meijiaka-zy/materials/2fb5183ef1547fb3d7d4d8e56fe5154a.mp4', 10.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '0d7081072e409e8f2c7d3a61a793f348', 'https://media.liche.cn/meijiaka-zy/materials/0d7081072e409e8f2c7d3a61a793f348.mp4', 10.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), 'f083bfca1800c171af2dfc767fc5d28a', 'https://media.liche.cn/meijiaka-zy/materials/f083bfca1800c171af2dfc767fc5d28a.mp4', 8.48, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '8e198970fe0be12c9067fefe658d1cdd', 'https://media.liche.cn/meijiaka-zy/materials/8e198970fe0be12c9067fefe658d1cdd.mp4', 9.8, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '3763505e431dc39a9fef135ad82ee6f1', 'https://media.liche.cn/meijiaka-zy/materials/3763505e431dc39a9fef135ad82ee6f1.mp4', 9.92, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '0576abe034e932071d7c3b67104e79c3', 'https://media.liche.cn/meijiaka-zy/materials/0576abe034e932071d7c3b67104e79c3.mp4', 9.9, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), '07281a59949dcaa72c22b54b8569e1ea', 'https://media.liche.cn/meijiaka-zy/materials/07281a59949dcaa72c22b54b8569e1ea.mp4', 4.71, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '装烟机灶具-主材安装镜' AND level = 3), 'e8d1429ec925636603b69b57ca3eba52', 'https://media.liche.cn/meijiaka-zy/materials/e8d1429ec925636603b69b57ca3eba52.mp4', 4.09, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '9d516288fc104f41e3a4c3747883a072', 'https://media.liche.cn/meijiaka-zy/materials/9d516288fc104f41e3a4c3747883a072.mp4', 6.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '8b293fcabbf5e8dc2f84a77e9cbb9956', 'https://media.liche.cn/meijiaka-zy/materials/8b293fcabbf5e8dc2f84a77e9cbb9956.mp4', 6.18, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '432a789688f8f729ec72ccbf8571820a', 'https://media.liche.cn/meijiaka-zy/materials/432a789688f8f729ec72ccbf8571820a.mp4', 10.0, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '3a97f3ebd82b3ff8c04ec47871199159', 'https://media.liche.cn/meijiaka-zy/materials/3a97f3ebd82b3ff8c04ec47871199159.mp4', 5.62, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), 'a67d0a41c10ea002968fb0ed1ad8ae0e', 'https://media.liche.cn/meijiaka-zy/materials/a67d0a41c10ea002968fb0ed1ad8ae0e.mp4', 8.55, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '6b28e44d37a14c3d9ac8b503a29a421c', 'https://media.liche.cn/meijiaka-zy/materials/6b28e44d37a14c3d9ac8b503a29a421c.mp4', 8.92, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), '9468e8aba0f47eeef9bc59e395bfcc72', 'https://media.liche.cn/meijiaka-zy/materials/9468e8aba0f47eeef9bc59e395bfcc72.mp4', 10.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '封窗施工-封窗镜' AND level = 3), 'b5d109f43246296ca6de51d28e596dcd', 'https://media.liche.cn/meijiaka-zy/materials/b5d109f43246296ca6de51d28e596dcd.mp4', 10.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), 'a15878e831df63d8cffc1066bf25e257', 'https://media.liche.cn/meijiaka-zy/materials/a15878e831df63d8cffc1066bf25e257.mp4', 7.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '1622140bd7229107b38927b831f8bea8', 'https://media.liche.cn/meijiaka-zy/materials/1622140bd7229107b38927b831f8bea8.mp4', 10.01, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '5ef57acfda494cfdfb5185594c51364c', 'https://media.liche.cn/meijiaka-zy/materials/5ef57acfda494cfdfb5185594c51364c.mp4', 7.85, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '4473c9736c25e77375459bd2968f4753', 'https://media.liche.cn/meijiaka-zy/materials/4473c9736c25e77375459bd2968f4753.mp4', 6.11, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '67526f381c629710d78c53ec3a2f6941', 'https://media.liche.cn/meijiaka-zy/materials/67526f381c629710d78c53ec3a2f6941.mp4', 5.2, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '1690725fa66d82b9400e462839328658', 'https://media.liche.cn/meijiaka-zy/materials/1690725fa66d82b9400e462839328658.mp4', 7.41, 0, 'active', NOW(), NOW()), - ((SELECT id FROM mjk_broll_categories WHERE name = '家具进场摆放就位-软装进场镜' AND level = 3), '28b67c0a7565ff259f889456334d000d', 'https://media.liche.cn/meijiaka-zy/materials/28b67c0a7565ff259f889456334d000d.mp4', 9.45, 0, 'active', NOW(), NOW()); \ No newline at end of file diff --git a/scripts/rename_viral_opening.py b/scripts/rename_viral_opening.py deleted file mode 100644 index d1c633d..0000000 --- a/scripts/rename_viral_opening.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -""" -网红开篇素材批量重命名脚本 -============================ - -按规则 md5(父目录名_原文件名) 重命名本地视频文件。 - -用法: - python3 scripts/rename_viral_opening.py - -效果: - /Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(13).mp4 - → /Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/2eaf1185....mp4 -""" - -import hashlib -import json -from pathlib import Path - - -def md5_filename(parent_name: str, original_name: str) -> str: - raw = f"{parent_name}_{original_name}" - return hashlib.md5(raw.encode("utf-8")).hexdigest() + ".mp4" - - -def main(): - src_dir = Path("/Users/0fun/Desktop/网红开篇") - renamed = [] - - for mp4_file in sorted(src_dir.rglob("*.mp4")): - if mp4_file.name.startswith("."): - continue - - parent_folder = mp4_file.parent.name - original_name = mp4_file.name - new_name = md5_filename(parent_folder, original_name) - - if mp4_file.name == new_name: - continue # 已经重命名过 - - new_path = mp4_file.parent / new_name - - print(f"{original_name}\n → {new_name}") - mp4_file.rename(new_path) - renamed.append({ - "original": original_name, - "new": new_name, - "folder": parent_folder, - "path": str(new_path), - }) - - print(f"\n✅ 共重命名 {len(renamed)} 个文件") - - # 保存重命名记录 - record = Path(__file__).parent / "viral_opening_renamed.json" - with open(record, "w", encoding="utf-8") as f: - json.dump(renamed, f, ensure_ascii=False, indent=2) - print(f"📄 记录已保存: {record}") - - -if __name__ == "__main__": - main() diff --git a/scripts/seed_bikeng_categories.sql b/scripts/seed_bikeng_categories.sql deleted file mode 100644 index 7f74e29..0000000 --- a/scripts/seed_bikeng_categories.sql +++ /dev/null @@ -1,202 +0,0 @@ --- 装修避坑通用素材分类体系 --- 共 86 个三级分类(68 个不要X要Y + 18 个买对不买贵) - -DO $$ -DECLARE - l1_id bigint; - l2_buyao_id bigint; - l2_maidui_id bigint; -BEGIN - - -- 一级:装修避坑通用 - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-tongyong', '装修避坑通用', NULL, 1, 90, 'active', NOW(), NOW()) - RETURNING id INTO l1_id; - - -- 二级:不要X要Y - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao', '不要X要Y', l1_id, 2, 1, 'active', NOW(), NOW()) - RETURNING id INTO l2_buyao_id; - - -- 二级:买对不买贵 - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui', '买对不买贵', l1_id, 2, 2, 'active', NOW(), NOW()) - RETURNING id INTO l2_maidui_id; - - -- 三级:不要X要Y(68个) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要一体式卫生间', '不要一体式卫生间', l2_buyao_id, 3, 1, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要双包套', '不要双包套', l2_buyao_id, 3, 2, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要双开门冰箱', '不要双开门冰箱', l2_buyao_id, 3, 3, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要反弹器', '不要反弹器', l2_buyao_id, 3, 4, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要回型吊顶', '不要回型吊顶', l2_buyao_id, 3, 5, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要复杂吊灯', '不要复杂吊灯', l2_buyao_id, 3, 6, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要复杂背景墙', '不要复杂背景墙', l2_buyao_id, 3, 7, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要小双槽', '不要小双槽', l2_buyao_id, 3, 8, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要开放式收纳柜', '不要开放式收纳柜', l2_buyao_id, 3, 9, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要悬浮电视柜', '不要悬浮电视柜', l2_buyao_id, 3, 10, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要悬空马桶', '不要悬空马桶', l2_buyao_id, 3, 11, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要拼色窗帘', '不要拼色窗帘', l2_buyao_id, 3, 12, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要推拉门', '不要推拉门', l2_buyao_id, 3, 13, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要插座外露', '不要插座外露', l2_buyao_id, 3, 14, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要无主灯', '不要无主灯', l2_buyao_id, 3, 15, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要普通门锁', '不要普通门锁', l2_buyao_id, 3, 16, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要榻榻米', '不要榻榻米', l2_buyao_id, 3, 17, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要正五孔插座', '不要正五孔插座', l2_buyao_id, 3, 18, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要洗烘一体', '不要洗烘一体', l2_buyao_id, 3, 19, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要深色地砖', '不要深色地砖', l2_buyao_id, 3, 20, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要猫眼', '不要猫眼', l2_buyao_id, 3, 21, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要瓷砖上墙', '不要瓷砖上墙', l2_buyao_id, 3, 22, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要直吸马桶', '不要直吸马桶', l2_buyao_id, 3, 23, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要直排下水', '不要直排下水', l2_buyao_id, 3, 24, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要筒灯', '不要筒灯', l2_buyao_id, 3, 25, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要罗马杠', '不要罗马杠', l2_buyao_id, 3, 26, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要贵妃椅沙发', '不要贵妃椅沙发', l2_buyao_id, 3, 27, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要路由器', '不要路由器', l2_buyao_id, 3, 28, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要过门石', '不要过门石', l2_buyao_id, 3, 29, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要造型柜门', '不要造型柜门', l2_buyao_id, 3, 30, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要阳角条', '不要阳角条', l2_buyao_id, 3, 31, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要隐形衣架', '不要隐形衣架', l2_buyao_id, 3, 32, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要集成灶', '不要集成灶', l2_buyao_id, 3, 33, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-不要高光衣柜门', '不要高光衣柜门', l2_buyao_id, 3, 34, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要一体门', '要一体门', l2_buyao_id, 3, 35, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要乳胶漆', '要乳胶漆', l2_buyao_id, 3, 36, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要免拉手', '要免拉手', l2_buyao_id, 3, 37, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要全屋wifi', '要全屋WiFi', l2_buyao_id, 3, 38, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要全屋通铺', '要全屋通铺', l2_buyao_id, 3, 39, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要分体灶', '要分体灶', l2_buyao_id, 3, 40, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要十字开门冰箱', '要十字开门冰箱', l2_buyao_id, 3, 41, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要单包套', '要单包套', l2_buyao_id, 3, 42, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要双眼皮', '要双眼皮', l2_buyao_id, 3, 43, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要双眼皮吊顶', '要双眼皮吊顶', l2_buyao_id, 3, 44, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要吸顶灯', '要吸顶灯', l2_buyao_id, 3, 45, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要墙排下水', '要墙排下水', l2_buyao_id, 3, 46, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要大单槽', '要大单槽', l2_buyao_id, 3, 47, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要封闭式收纳柜', '要封闭式收纳柜', l2_buyao_id, 3, 48, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要射灯', '要射灯', l2_buyao_id, 3, 49, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要干湿分离卫生间', '要干湿分离卫生间', l2_buyao_id, 3, 50, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要平板柜门', '要平板柜门', l2_buyao_id, 3, 51, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要打通阳台', '要打通阳台', l2_buyao_id, 3, 52, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要斜五孔插座', '要斜五孔插座', l2_buyao_id, 3, 53, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要普通床', '要普通床', l2_buyao_id, 3, 54, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要普通衣架', '要普通衣架', l2_buyao_id, 3, 55, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要智能门锁', '要智能门锁', l2_buyao_id, 3, 56, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要洗烘套装', '要洗烘套装', l2_buyao_id, 3, 57, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要浅色地砖', '要浅色地砖', l2_buyao_id, 3, 58, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要海棠角', '要海棠角', l2_buyao_id, 3, 59, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要直排沙发', '要直排沙发', l2_buyao_id, 3, 60, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要窗帘盒', '要窗帘盒', l2_buyao_id, 3, 61, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要简约背景墙', '要简约背景墙', l2_buyao_id, 3, 62, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要纯色窗帘', '要纯色窗帘', l2_buyao_id, 3, 63, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要肤感衣柜门', '要肤感衣柜门', l2_buyao_id, 3, 64, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要落地电视柜', '要落地电视柜', l2_buyao_id, 3, 65, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要落地马桶', '要落地马桶', l2_buyao_id, 3, 66, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要虹吸马桶', '要虹吸马桶', l2_buyao_id, 3, 67, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-buyao-要隐藏式插座', '要隐藏式插座', l2_buyao_id, 3, 68, 'active', NOW(), NOW()); - - -- 三级:买对不买贵(18个) - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-乳胶漆不要买贵的', '乳胶漆不要买贵的', l2_maidui_id, 3, 1, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-全屋角阀要买贵的', '全屋角阀要买贵的', l2_maidui_id, 3, 2, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-前置过滤器不要买贵的', '前置过滤器不要买贵的', l2_maidui_id, 3, 3, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-床不要买贵的', '床不要买贵的', l2_maidui_id, 3, 4, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-床垫要买贵的', '床垫要买贵的', l2_maidui_id, 3, 5, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-开关插座要买贵的', '开关插座要买贵的', l2_maidui_id, 3, 6, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-投影仪要买贵的', '投影仪要买贵的', l2_maidui_id, 3, 7, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-木地板要买贵的', '木地板要买贵的', l2_maidui_id, 3, 8, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-木门不要买贵的', '木门不要买贵的', l2_maidui_id, 3, 9, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-水槽不要买贵的', '水槽不要买贵的', l2_maidui_id, 3, 10, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-水龙头要买贵的', '水龙头要买贵的', l2_maidui_id, 3, 11, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-滑轨要买贵的', '滑轨要买贵的', l2_maidui_id, 3, 12, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-灯具不要买贵的', '灯具不要买贵的', l2_maidui_id, 3, 13, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-瓷砖不要买贵的', '瓷砖不要买贵的', l2_maidui_id, 3, 14, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-电视机不要买贵的', '电视机不要买贵的', l2_maidui_id, 3, 15, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-窗帘不要买贵的', '窗帘不要买贵的', l2_maidui_id, 3, 16, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-腻子粉要买贵的', '腻子粉要买贵的', l2_maidui_id, 3, 17, 'active', NOW(), NOW()); - INSERT INTO mjk_broll_categories (slug, name, parent_id, level, sort_order, status, created_at, updated_at) - VALUES ('bikeng-maidui-门锁要买贵的', '门锁要买贵的', l2_maidui_id, 3, 18, 'active', NOW(), NOW()); - -END $$; diff --git a/scripts/upload_new_materials_6.2.sh b/scripts/upload_new_materials_6.2.sh deleted file mode 100755 index 41d6f17..0000000 --- a/scripts/upload_new_materials_6.2.sh +++ /dev/null @@ -1,203 +0,0 @@ -#!/bin/bash -# 新增素材6.2 批量上传脚本 - -# 万华爱格兔宝宝 (5.0s) -qshell fput meijiaka-zy materials/3c28619290414e552e988e09b3675b72.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/万华爱格兔宝宝/3c28619290414e552e988e09b3675b72.mp4' - -# 东鹏冠珠马可波罗 (5.01s) -qshell fput meijiaka-zy materials/182e4c8bbcea8f103672b147b4606213.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/东鹏冠珠马可波罗/182e4c8bbcea8f103672b147b4606213.mp4' - -# 九牧恒洁箭牌 (5.01s) -qshell fput meijiaka-zy materials/7d5607ab1886ba948fc1e94398473274.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/九牧恒洁箭牌/7d5607ab1886ba948fc1e94398473274.mp4' - -# 九牧箭牌潜水艇 (5.01s) -qshell fput meijiaka-zy materials/6924bfd00653c3c6cfcb2d1d02c4789c.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/九牧箭牌潜水艇/6924bfd00653c3c6cfcb2d1d02c4789c.mp4' - -# 乳胶漆买谁家 (3.0s) -qshell fput meijiaka-zy materials/6086a32ec41db26e5bc570f1f27c1fbc.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/乳胶漆买谁家/6086a32ec41db26e5bc570f1f27c1fbc.mp4' - -# 公牛施耐德西门子 (5.01s) -qshell fput meijiaka-zy materials/c0a3e230b32026b78596c192718345cb.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/公牛施耐德西门子/c0a3e230b32026b78596c192718345cb.mp4' - -# 冰箱买谁家 (3.0s) -qshell fput meijiaka-zy materials/fad1e564d3272515eab8dd75079870de.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/冰箱买谁家/fad1e564d3272515eab8dd75079870de.mp4' - -# 厨卫五金谁家好 (3.0s) -qshell fput meijiaka-zy materials/4d20e0593c973366e064451fd9561eff.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/厨卫五金谁家好/4d20e0593c973366e064451fd9561eff.mp4' - -# 吊顶选谁家 (3.0s) -qshell fput meijiaka-zy materials/4ee89978139e0e55c809aedf5a56ddc2.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/吊顶选谁家/4ee89978139e0e55c809aedf5a56ddc2.mp4' - -# 圣象世友大自然 (5.01s) -qshell fput meijiaka-zy materials/5c78732634c008867211a9a34d124881.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/圣象世友大自然/5c78732634c008867211a9a34d124881.mp4' - -# 地板哪家好 (3.0s) -qshell fput meijiaka-zy materials/647972fffa483aa807ecd08ed53219be.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/地板哪家好/647972fffa483aa807ecd08ed53219be.mp4' - -# 地漏谁家好 (3.0s) -qshell fput meijiaka-zy materials/d4fb5c1a8bf3cecf8662f82b6977a954.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/地漏谁家好/d4fb5c1a8bf3cecf8662f82b6977a954.mp4' - -# 奥普友邦法狮龙 (5.01s) -qshell fput meijiaka-zy materials/a6cc0fb2a45ea0e4b988451baddac499.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/奥普友邦法狮龙/a6cc0fb2a45ea0e4b988451baddac499.mp4' - -# 家装水泥谁家好 (3.0s) -qshell fput meijiaka-zy materials/e189e0507cd2ecb0be2e32d2cf65dccd.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/家装水泥谁家好/e189e0507cd2ecb0be2e32d2cf65dccd.mp4' - -# 家装水管谁家好 (3.0s) -qshell fput meijiaka-zy materials/72d9643978717084039cf3507f9bdd04.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/家装水管谁家好/72d9643978717084039cf3507f9bdd04.mp4' - -# 开关插座买谁家 (3.0s) -qshell fput meijiaka-zy materials/8df9cfec100cea2661784361571a3a11.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/开关插座买谁家/8df9cfec100cea2661784361571a3a11.mp4' - -# 德高西卡马贝 (5.01s) -qshell fput meijiaka-zy materials/b365eb193c1ede5777cc04d2427ea0e7.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/德高西卡马贝/b365eb193c1ede5777cc04d2427ea0e7.mp4' - -# 方太老板华帝 (5.01s) -qshell fput meijiaka-zy materials/9e37037aad90b25493228d05c0405696.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/方太老板华帝/9e37037aad90b25493228d05c0405696.mp4' - -# 日丰伟星保利 (5.01s) -qshell fput meijiaka-zy materials/3318c054d10f5ecca8ce397f435c01af.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/日丰伟星保利/3318c054d10f5ecca8ce397f435c01af.mp4' - -# 板材选谁家 (3.0s) -qshell fput meijiaka-zy materials/9e5eb608644425a51613e2e145ba28e0.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/板材选谁家/9e5eb608644425a51613e2e145ba28e0.mp4' - -# 水管买谁家 (3.0s) -qshell fput meijiaka-zy materials/0d37b9dbf4b44858f16f155ba88a7054.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/水管买谁家/0d37b9dbf4b44858f16f155ba88a7054.mp4' - -# 海尔美的卡萨帝 (5.01s) -qshell fput meijiaka-zy materials/33e3a3ae93f65e72d055431b0d132495.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/海尔美的卡萨帝/33e3a3ae93f65e72d055431b0d132495.mp4' - -# 海螺红狮中联 (5.01s) -qshell fput meijiaka-zy materials/cd7f119729a062df350940bb003f873d.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/海螺红狮中联/cd7f119729a062df350940bb003f873d.mp4' - -# 烟机哪家好 (3.0s) -qshell fput meijiaka-zy materials/01690f5d76a40142f365da61319c9f31.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/烟机哪家好/01690f5d76a40142f365da61319c9f31.mp4' - -# 玻璃胶谁家好 (3.0s) -qshell fput meijiaka-zy materials/52d7c9db8291af1d9e2061c3288bec2b.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/玻璃胶谁家好/52d7c9db8291af1d9e2061c3288bec2b.mp4' - -# 瓦克西卡百得 (5.01s) -qshell fput meijiaka-zy materials/1e2774b366631016acecc03c322dc0a2.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/瓦克西卡百得/1e2774b366631016acecc03c322dc0a2.mp4' - -# 瓷砖哪家好 (3.0s) -qshell fput meijiaka-zy materials/e727f0ea33030c14d33185329794398c.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/瓷砖哪家好/e727f0ea33030c14d33185329794398c.mp4' - -# 瓷砖胶谁家好 (3.0s) -qshell fput meijiaka-zy materials/07a1f9a9ec09809d33781a2b6265ff48.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/瓷砖胶谁家好/07a1f9a9ec09809d33781a2b6265ff48.mp4' - -# 电线买谁家 (3.0s) -qshell fput meijiaka-zy materials/04f61f5a57454799d2aa1000764311af.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/电线买谁家/04f61f5a57454799d2aa1000764311af.mp4' - -# 电视买谁家 (3.0s) -qshell fput meijiaka-zy materials/82c400fbc27c42dd8992458d2e94c047.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/电视买谁家/82c400fbc27c42dd8992458d2e94c047.mp4' - -# 石膏板谁家好 (3.0s) -qshell fput meijiaka-zy materials/e6469a2dc66350c330d2d87f08a9cd5a.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/石膏板谁家好/e6469a2dc66350c330d2d87f08a9cd5a.mp4' - -# 科勒九牧汉斯格雅 (5.01s) -qshell fput meijiaka-zy materials/80506a9eb5e1a06d3c5cb98eaae515cd.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/科勒九牧汉斯格雅/80506a9eb5e1a06d3c5cb98eaae515cd.mp4' - -# 立邦三棵树多乐士 (5.01s) -qshell fput meijiaka-zy materials/82b26195cdb7a08793abf3ff17d400eb.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/立邦三棵树多乐士/82b26195cdb7a08793abf3ff17d400eb.mp4' - -# 立邦德高东方雨虹 (5.01s) -qshell fput meijiaka-zy materials/03602a66190ad519f81c70a80e6cd0d2.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/立邦德高东方雨虹/03602a66190ad519f81c70a80e6cd0d2.mp4' - -# 立邦美巢圣戈邦 (5.01s) -qshell fput meijiaka-zy materials/cc00321964988a29315468e4dca53d06.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/立邦美巢圣戈邦/cc00321964988a29315468e4dca53d06.mp4' - -# 索尼海信TCL (5.01s) -qshell fput meijiaka-zy materials/fb9d3b062be7ed44fef7ec81490a4963.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/索尼海信TCL/fb9d3b062be7ed44fef7ec81490a4963.mp4' - -# 腻子粉哪家好 (3.0s) -qshell fput meijiaka-zy materials/887c5ea3238d2c1196eb09c410dc8f7f.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/腻子粉哪家好/887c5ea3238d2c1196eb09c410dc8f7f.mp4' - -# 花洒哪家好 (3.0s) -qshell fput meijiaka-zy materials/f6d4592e08482cb903daca04d432f3ed.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/花洒哪家好/f6d4592e08482cb903daca04d432f3ed.mp4' - -# 远东宝胜熊猫 (5.01s) -qshell fput meijiaka-zy materials/c5ac8d8ff5435e123c8016657fbf955c.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/远东宝胜熊猫/c5ac8d8ff5435e123c8016657fbf955c.mp4' - -# 金牛伟星日丰 (5.01s) -qshell fput meijiaka-zy materials/3c9546527a38c300050ed28bda81e204.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/金牛伟星日丰/3c9546527a38c300050ed28bda81e204.mp4' - -# 防水买谁家 (3.0s) -qshell fput meijiaka-zy materials/3e7c5b554836376605828f374bd15ae5.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/防水买谁家/3e7c5b554836376605828f374bd15ae5.mp4' - -# 龙牌泰山可耐福 (5.01s) -qshell fput meijiaka-zy materials/6589ffbf04c596583d2d2316216c7428.mp4 '/Users/0fun/Downloads/新增素材6.2/其他/装修材料选择/龙牌泰山可耐福/6589ffbf04c596583d2d2316216c7428.mp4' - -# 装烟机灶具-主材安装镜 (10.01s) -qshell fput meijiaka-zy materials/488d5a9ac72bf8e9a2a574284f2bdded.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/488d5a9ac72bf8e9a2a574284f2bdded.mp4' - -# 装烟机灶具-主材安装镜 (9.97s) -qshell fput meijiaka-zy materials/3c716b567964591569abfc8d16e7ff9b.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/3c716b567964591569abfc8d16e7ff9b.mp4' - -# 装烟机灶具-主材安装镜 (10.01s) -qshell fput meijiaka-zy materials/2fb5183ef1547fb3d7d4d8e56fe5154a.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/2fb5183ef1547fb3d7d4d8e56fe5154a.mp4' - -# 装烟机灶具-主材安装镜 (10.01s) -qshell fput meijiaka-zy materials/0d7081072e409e8f2c7d3a61a793f348.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/0d7081072e409e8f2c7d3a61a793f348.mp4' - -# 装烟机灶具-主材安装镜 (8.48s) -qshell fput meijiaka-zy materials/f083bfca1800c171af2dfc767fc5d28a.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/f083bfca1800c171af2dfc767fc5d28a.mp4' - -# 装烟机灶具-主材安装镜 (9.8s) -qshell fput meijiaka-zy materials/8e198970fe0be12c9067fefe658d1cdd.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/8e198970fe0be12c9067fefe658d1cdd.mp4' - -# 装烟机灶具-主材安装镜 (9.92s) -qshell fput meijiaka-zy materials/3763505e431dc39a9fef135ad82ee6f1.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/3763505e431dc39a9fef135ad82ee6f1.mp4' - -# 装烟机灶具-主材安装镜 (9.9s) -qshell fput meijiaka-zy materials/0576abe034e932071d7c3b67104e79c3.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/0576abe034e932071d7c3b67104e79c3.mp4' - -# 装烟机灶具-主材安装镜 (4.71s) -qshell fput meijiaka-zy materials/07281a59949dcaa72c22b54b8569e1ea.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/07281a59949dcaa72c22b54b8569e1ea.mp4' - -# 装烟机灶具-主材安装镜 (4.09s) -qshell fput meijiaka-zy materials/e8d1429ec925636603b69b57ca3eba52.mp4 '/Users/0fun/Downloads/新增素材6.2/安装收尾类/电器安装/装烟机灶具/e8d1429ec925636603b69b57ca3eba52.mp4' - -# 封窗施工-封窗镜 (6.01s) -qshell fput meijiaka-zy materials/9d516288fc104f41e3a4c3747883a072.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/9d516288fc104f41e3a4c3747883a072.mp4' - -# 封窗施工-封窗镜 (6.18s) -qshell fput meijiaka-zy materials/8b293fcabbf5e8dc2f84a77e9cbb9956.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/8b293fcabbf5e8dc2f84a77e9cbb9956.mp4' - -# 封窗施工-封窗镜 (10.0s) -qshell fput meijiaka-zy materials/432a789688f8f729ec72ccbf8571820a.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/432a789688f8f729ec72ccbf8571820a.mp4' - -# 封窗施工-封窗镜 (5.62s) -qshell fput meijiaka-zy materials/3a97f3ebd82b3ff8c04ec47871199159.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/3a97f3ebd82b3ff8c04ec47871199159.mp4' - -# 封窗施工-封窗镜 (8.55s) -qshell fput meijiaka-zy materials/a67d0a41c10ea002968fb0ed1ad8ae0e.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/a67d0a41c10ea002968fb0ed1ad8ae0e.mp4' - -# 封窗施工-封窗镜 (8.92s) -qshell fput meijiaka-zy materials/6b28e44d37a14c3d9ac8b503a29a421c.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/6b28e44d37a14c3d9ac8b503a29a421c.mp4' - -# 封窗施工-封窗镜 (10.2s) -qshell fput meijiaka-zy materials/9468e8aba0f47eeef9bc59e395bfcc72.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/9468e8aba0f47eeef9bc59e395bfcc72.mp4' - -# 封窗施工-封窗镜 (10.01s) -qshell fput meijiaka-zy materials/b5d109f43246296ca6de51d28e596dcd.mp4 '/Users/0fun/Downloads/新增素材6.2/拆改改造类/封窗/封窗施工/b5d109f43246296ca6de51d28e596dcd.mp4' - -# 家具进场摆放就位-软装进场镜 (7.01s) -qshell fput meijiaka-zy materials/a15878e831df63d8cffc1066bf25e257.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/a15878e831df63d8cffc1066bf25e257.mp4' - -# 家具进场摆放就位-软装进场镜 (10.01s) -qshell fput meijiaka-zy materials/1622140bd7229107b38927b831f8bea8.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/1622140bd7229107b38927b831f8bea8.mp4' - -# 家具进场摆放就位-软装进场镜 (7.85s) -qshell fput meijiaka-zy materials/5ef57acfda494cfdfb5185594c51364c.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/5ef57acfda494cfdfb5185594c51364c.mp4' - -# 家具进场摆放就位-软装进场镜 (6.11s) -qshell fput meijiaka-zy materials/4473c9736c25e77375459bd2968f4753.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/4473c9736c25e77375459bd2968f4753.mp4' - -# 家具进场摆放就位-软装进场镜 (5.2s) -qshell fput meijiaka-zy materials/67526f381c629710d78c53ec3a2f6941.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/67526f381c629710d78c53ec3a2f6941.mp4' - -# 家具进场摆放就位-软装进场镜 (7.41s) -qshell fput meijiaka-zy materials/1690725fa66d82b9400e462839328658.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/1690725fa66d82b9400e462839328658.mp4' - -# 家具进场摆放就位-软装进场镜 (9.45s) -qshell fput meijiaka-zy materials/28b67c0a7565ff259f889456334d000d.mp4 '/Users/0fun/Downloads/新增素材6.2/软装完工&验收类/软装进场镜/家具进场摆放就位-软装进场/28b67c0a7565ff259f889456334d000d.mp4' diff --git a/scripts/viral_opening_insert.sql b/scripts/viral_opening_insert.sql deleted file mode 100644 index b29dd6f..0000000 --- a/scripts/viral_opening_insert.sql +++ /dev/null @@ -1,211 +0,0 @@ --- 网红开篇素材入库 SQL --- 共 41 个视频 - -BEGIN; - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'b3aff6db0536a8d7f51277bd17a449b3.mp4', 'https://media.liche.cn/meijiaka-zy/materials/b3aff6db0536a8d7f51277bd17a449b3.mp4', 4.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 4.02s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '845c6856746752c319239869d03d2def.mp4', 'https://media.liche.cn/meijiaka-zy/materials/845c6856746752c319239869d03d2def.mp4', 4.5, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 4.5s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '4819ccec34b556b6a686503c8496d2d2.mp4', 'https://media.liche.cn/meijiaka-zy/materials/4819ccec34b556b6a686503c8496d2d2.mp4', 9.17, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 9.17s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '2073d7ca41856cc162ac3a86881eeee8.mp4', 'https://media.liche.cn/meijiaka-zy/materials/2073d7ca41856cc162ac3a86881eeee8.mp4', 6.32, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 6.32s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '0097dceb9c7218d66f4b31d9ad47aee3.mp4', 'https://media.liche.cn/meijiaka-zy/materials/0097dceb9c7218d66f4b31d9ad47aee3.mp4', 5.43, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 5.43s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '811ad18d3f8e5cf3792460e4aabf1744.mp4', 'https://media.liche.cn/meijiaka-zy/materials/811ad18d3f8e5cf3792460e4aabf1744.mp4', 5.2, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 5.2s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '7f1ec7aeab78ee64171fa6685c4439fc.mp4', 'https://media.liche.cn/meijiaka-zy/materials/7f1ec7aeab78ee64171fa6685c4439fc.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 8.01s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'df3223bb4de53e197ddd944ed5d2e5d5.mp4', 'https://media.liche.cn/meijiaka-zy/materials/df3223bb4de53e197ddd944ed5d2e5d5.mp4', 8.8, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 8.8s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'a2c9adea107f99cdc5f6fb6b02236579.mp4', 'https://media.liche.cn/meijiaka-zy/materials/a2c9adea107f99cdc5f6fb6b02236579.mp4', 7.11, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 7.11s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'c77b5e546cb0393a5e7c3c4cea3bebb2.mp4', 'https://media.liche.cn/meijiaka-zy/materials/c77b5e546cb0393a5e7c3c4cea3bebb2.mp4', 6.62, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 6.62s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'a29f7c2ffa5a39326d6aed18f0c6df8d.mp4', 'https://media.liche.cn/meijiaka-zy/materials/a29f7c2ffa5a39326d6aed18f0c6df8d.mp4', 5.04, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 5.04s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'e7cc059acaca9d9286c547c1f9f3c39f.mp4', 'https://media.liche.cn/meijiaka-zy/materials/e7cc059acaca9d9286c547c1f9f3c39f.mp4', 5.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xjhm' AND level = 3; --- 来源: 吸睛画面-恶搞开篇 | 时长: 5.02s | 分类: wanghong-egao-xjhm - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '8c5bbf96530c1a03b9f084d13e06c7c9.mp4', 'https://media.liche.cn/meijiaka-zy/materials/8c5bbf96530c1a03b9f084d13e06c7c9.mp4', 7.34, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 7.34s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '24c662049e2db23c8ad8e39b188d769c.mp4', 'https://media.liche.cn/meijiaka-zy/materials/24c662049e2db23c8ad8e39b188d769c.mp4', 5.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 5.02s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '6f9c760668d743102ae4e6e0943a658f.mp4', 'https://media.liche.cn/meijiaka-zy/materials/6f9c760668d743102ae4e6e0943a658f.mp4', 4.25, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 4.25s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '44622ad5abe2e66279550bc7f95dcc6b.mp4', 'https://media.liche.cn/meijiaka-zy/materials/44622ad5abe2e66279550bc7f95dcc6b.mp4', 6.08, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 6.08s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '4f2290dd81773eaada0a3a0cc8adf115.mp4', 'https://media.liche.cn/meijiaka-zy/materials/4f2290dd81773eaada0a3a0cc8adf115.mp4', 5.04, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 5.04s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '8021088c304e09ac93929660530d68ab.mp4', 'https://media.liche.cn/meijiaka-zy/materials/8021088c304e09ac93929660530d68ab.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 8.01s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'b25deff3d658d6b5e1f82715d5b32e6c.mp4', 'https://media.liche.cn/meijiaka-zy/materials/b25deff3d658d6b5e1f82715d5b32e6c.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 8.01s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '93e95bedaf905e63613d5971ecbde77d.mp4', 'https://media.liche.cn/meijiaka-zy/materials/93e95bedaf905e63613d5971ecbde77d.mp4', 5.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 5.02s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '17705678ad0757af9e70fd1ca4579882.mp4', 'https://media.liche.cn/meijiaka-zy/materials/17705678ad0757af9e70fd1ca4579882.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gdeg' AND level = 3; --- 来源: 工地恶搞-恶搞开篇 | 时长: 8.01s | 分类: wanghong-egao-gdeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '6ea04c0905384386643a43ad3d8c62e8.mp4', 'https://media.liche.cn/meijiaka-zy/materials/6ea04c0905384386643a43ad3d8c62e8.mp4', 4.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 4.02s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'c1c71478b19779df6d6231c76147c00e.mp4', 'https://media.liche.cn/meijiaka-zy/materials/c1c71478b19779df6d6231c76147c00e.mp4', 4.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 4.02s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'fd03a112a4b9e7edc4534648d17b5cff.mp4', 'https://media.liche.cn/meijiaka-zy/materials/fd03a112a4b9e7edc4534648d17b5cff.mp4', 4.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 4.02s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '70ea7edb5173568fa8079da9fe7da0bf.mp4', 'https://media.liche.cn/meijiaka-zy/materials/70ea7edb5173568fa8079da9fe7da0bf.mp4', 7.34, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 7.34s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '688a3f761f110c7ce320a7a124baf191.mp4', 'https://media.liche.cn/meijiaka-zy/materials/688a3f761f110c7ce320a7a124baf191.mp4', 5.04, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 5.04s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '0750b373b8d293020e593c0fb6ca973b.mp4', 'https://media.liche.cn/meijiaka-zy/materials/0750b373b8d293020e593c0fb6ca973b.mp4', 4.11, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 4.11s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '33a38a924ca3ee44ae651c452b742799.mp4', 'https://media.liche.cn/meijiaka-zy/materials/33a38a924ca3ee44ae651c452b742799.mp4', 5.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-gxtlsg' AND level = 3; --- 来源: 搞笑涂料施工-恶搞开篇 | 时长: 5.02s | 分类: wanghong-egao-gxtlsg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '2eaf1185874d48136e3fbc62e908d455.mp4', 'https://media.liche.cn/meijiaka-zy/materials/2eaf1185874d48136e3fbc62e908d455.mp4', 4.25, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-blcc' AND level = 3; --- 来源: 暴力拆除-恶搞开篇 | 时长: 4.25s | 分类: wanghong-egao-blcc - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'd9fe52d52a13c5fcd15736f342f082fe.mp4', 'https://media.liche.cn/meijiaka-zy/materials/d9fe52d52a13c5fcd15736f342f082fe.mp4', 7.62, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-blcc' AND level = 3; --- 来源: 暴力拆除-恶搞开篇 | 时长: 7.62s | 分类: wanghong-egao-blcc - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'c252875cd6948d0f38062cb07538194d.mp4', 'https://media.liche.cn/meijiaka-zy/materials/c252875cd6948d0f38062cb07538194d.mp4', 6.78, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-blcc' AND level = 3; --- 来源: 暴力拆除-恶搞开篇 | 时长: 6.78s | 分类: wanghong-egao-blcc - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'dd1cee83a3366ff11bd00df286193d0b.mp4', 'https://media.liche.cn/meijiaka-zy/materials/dd1cee83a3366ff11bd00df286193d0b.mp4', 6.34, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-blcc' AND level = 3; --- 来源: 暴力拆除-恶搞开篇 | 时长: 6.34s | 分类: wanghong-egao-blcc - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'e36d1bceeebaadf20ccc5f8dfeb1ab97.mp4', 'https://media.liche.cn/meijiaka-zy/materials/e36d1bceeebaadf20ccc5f8dfeb1ab97.mp4', 3.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xj' AND level = 3; --- 来源: 炫技-恶搞开篇 | 时长: 3.02s | 分类: wanghong-egao-xj - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'a19a83b9a3b5f32daf154a46b457bb69.mp4', 'https://media.liche.cn/meijiaka-zy/materials/a19a83b9a3b5f32daf154a46b457bb69.mp4', 3.55, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xj' AND level = 3; --- 来源: 炫技-恶搞开篇 | 时长: 3.55s | 分类: wanghong-egao-xj - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '92baf7b9594e89c5f366fb77168a4879.mp4', 'https://media.liche.cn/meijiaka-zy/materials/92baf7b9594e89c5f366fb77168a4879.mp4', 4.02, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xj' AND level = 3; --- 来源: 炫技-恶搞开篇 | 时长: 4.02s | 分类: wanghong-egao-xj - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, 'a2c58cb2c6a1f2c1dec111f2fcefecc8.mp4', 'https://media.liche.cn/meijiaka-zy/materials/a2c58cb2c6a1f2c1dec111f2fcefecc8.mp4', 5.04, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-xj' AND level = 3; --- 来源: 炫技-恶搞开篇 | 时长: 5.04s | 分类: wanghong-egao-xj - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '62d4bc30cccf74a3300f40c3952470d3.mp4', 'https://media.liche.cn/meijiaka-zy/materials/62d4bc30cccf74a3300f40c3952470d3.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-tzeg' AND level = 3; --- 来源: 贴砖恶搞-恶搞开篇 | 时长: 8.01s | 分类: wanghong-egao-tzeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '9a134ff2649212d5f33069c850df385f.mp4', 'https://media.liche.cn/meijiaka-zy/materials/9a134ff2649212d5f33069c850df385f.mp4', 9.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-tzeg' AND level = 3; --- 来源: 贴砖恶搞-恶搞开篇 | 时长: 9.01s | 分类: wanghong-egao-tzeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '00d6b249ce62c2553a23e3d93e460d91.mp4', 'https://media.liche.cn/meijiaka-zy/materials/00d6b249ce62c2553a23e3d93e460d91.mp4', 8.03, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-egao-tzeg' AND level = 3; --- 来源: 贴砖恶搞-恶搞开篇 | 时长: 8.03s | 分类: wanghong-egao-tzeg - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '73e70b1aacab4e4ddaa06f361ff1c07e.mp4', 'https://media.liche.cn/meijiaka-zy/materials/73e70b1aacab4e4ddaa06f361ff1c07e.mp4', 8.01, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-fanche-fsfcls' AND level = 3; --- 来源: 防水翻车漏水-施工翻车镜 | 时长: 8.01s | 分类: wanghong-fanche-fsfcls - -INSERT INTO mjk_broll_materials (category_id, title, url, duration, usage_count, status, created_at, updated_at) -SELECT id, '6d770fb02e2bbb6000b8123fe5a9fb55.mp4', 'https://media.liche.cn/meijiaka-zy/materials/6d770fb02e2bbb6000b8123fe5a9fb55.mp4', 7.5, 0, 'active', NOW(), NOW() -FROM mjk_broll_categories WHERE slug = 'wanghong-fanche-fsfcls' AND level = 3; --- 来源: 防水翻车漏水-施工翻车镜 | 时长: 7.5s | 分类: wanghong-fanche-fsfcls - -COMMIT; diff --git a/scripts/viral_opening_upload.sh b/scripts/viral_opening_upload.sh deleted file mode 100755 index 83259f8..0000000 --- a/scripts/viral_opening_upload.sh +++ /dev/null @@ -1,167 +0,0 @@ -#!/bin/bash -# 网红开篇素材批量上传脚本 - -# 吸睛画面-恶搞开篇/5月16日(19).mp4 (4.02s) -# qshell put meijiaka-zy materials/b3aff6db0536a8d7f51277bd17a449b3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(19).mp4' -# 或: qshell fput meijiaka-zy materials/b3aff6db0536a8d7f51277bd17a449b3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(19).mp4' - -# 吸睛画面-恶搞开篇/5月16日(23).mp4 (4.5s) -# qshell put meijiaka-zy materials/845c6856746752c319239869d03d2def.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(23).mp4' -# 或: qshell fput meijiaka-zy materials/845c6856746752c319239869d03d2def.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(23).mp4' - -# 吸睛画面-恶搞开篇/5月16日(24).mp4 (9.17s) -# qshell put meijiaka-zy materials/4819ccec34b556b6a686503c8496d2d2.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(24).mp4' -# 或: qshell fput meijiaka-zy materials/4819ccec34b556b6a686503c8496d2d2.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(24).mp4' - -# 吸睛画面-恶搞开篇/5月16日(26).mp4 (6.32s) -# qshell put meijiaka-zy materials/2073d7ca41856cc162ac3a86881eeee8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(26).mp4' -# 或: qshell fput meijiaka-zy materials/2073d7ca41856cc162ac3a86881eeee8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(26).mp4' - -# 吸睛画面-恶搞开篇/5月16日(27).mp4 (5.43s) -# qshell put meijiaka-zy materials/0097dceb9c7218d66f4b31d9ad47aee3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(27).mp4' -# 或: qshell fput meijiaka-zy materials/0097dceb9c7218d66f4b31d9ad47aee3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(27).mp4' - -# 吸睛画面-恶搞开篇/5月16日(33).mp4 (5.2s) -# qshell put meijiaka-zy materials/811ad18d3f8e5cf3792460e4aabf1744.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(33).mp4' -# 或: qshell fput meijiaka-zy materials/811ad18d3f8e5cf3792460e4aabf1744.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(33).mp4' - -# 吸睛画面-恶搞开篇/5月16日(36).mp4 (8.01s) -# qshell put meijiaka-zy materials/7f1ec7aeab78ee64171fa6685c4439fc.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(36).mp4' -# 或: qshell fput meijiaka-zy materials/7f1ec7aeab78ee64171fa6685c4439fc.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(36).mp4' - -# 吸睛画面-恶搞开篇/5月16日(37).mp4 (8.8s) -# qshell put meijiaka-zy materials/df3223bb4de53e197ddd944ed5d2e5d5.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(37).mp4' -# 或: qshell fput meijiaka-zy materials/df3223bb4de53e197ddd944ed5d2e5d5.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(37).mp4' - -# 吸睛画面-恶搞开篇/5月16日(38).mp4 (7.11s) -# qshell put meijiaka-zy materials/a2c9adea107f99cdc5f6fb6b02236579.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(38).mp4' -# 或: qshell fput meijiaka-zy materials/a2c9adea107f99cdc5f6fb6b02236579.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(38).mp4' - -# 吸睛画面-恶搞开篇/5月16日(39).mp4 (6.62s) -# qshell put meijiaka-zy materials/c77b5e546cb0393a5e7c3c4cea3bebb2.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(39).mp4' -# 或: qshell fput meijiaka-zy materials/c77b5e546cb0393a5e7c3c4cea3bebb2.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(39).mp4' - -# 吸睛画面-恶搞开篇/5月16日(4).mp4 (5.04s) -# qshell put meijiaka-zy materials/a29f7c2ffa5a39326d6aed18f0c6df8d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(4).mp4' -# 或: qshell fput meijiaka-zy materials/a29f7c2ffa5a39326d6aed18f0c6df8d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(4).mp4' - -# 吸睛画面-恶搞开篇/5月16日(8).mp4 (5.02s) -# qshell put meijiaka-zy materials/e7cc059acaca9d9286c547c1f9f3c39f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(8).mp4' -# 或: qshell fput meijiaka-zy materials/e7cc059acaca9d9286c547c1f9f3c39f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/吸睛画面-恶搞开篇/5月16日(8).mp4' - -# 工地恶搞-恶搞开篇/5月16日(1).mp4 (7.34s) -# qshell put meijiaka-zy materials/8c5bbf96530c1a03b9f084d13e06c7c9.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(1).mp4' -# 或: qshell fput meijiaka-zy materials/8c5bbf96530c1a03b9f084d13e06c7c9.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(1).mp4' - -# 工地恶搞-恶搞开篇/5月16日(12).mp4 (5.02s) -# qshell put meijiaka-zy materials/24c662049e2db23c8ad8e39b188d769c.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(12).mp4' -# 或: qshell fput meijiaka-zy materials/24c662049e2db23c8ad8e39b188d769c.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(12).mp4' - -# 工地恶搞-恶搞开篇/5月16日(14).mp4 (4.25s) -# qshell put meijiaka-zy materials/6f9c760668d743102ae4e6e0943a658f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(14).mp4' -# 或: qshell fput meijiaka-zy materials/6f9c760668d743102ae4e6e0943a658f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(14).mp4' - -# 工地恶搞-恶搞开篇/5月16日(25).mp4 (6.08s) -# qshell put meijiaka-zy materials/44622ad5abe2e66279550bc7f95dcc6b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(25).mp4' -# 或: qshell fput meijiaka-zy materials/44622ad5abe2e66279550bc7f95dcc6b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(25).mp4' - -# 工地恶搞-恶搞开篇/5月16日(3).mp4 (5.04s) -# qshell put meijiaka-zy materials/4f2290dd81773eaada0a3a0cc8adf115.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(3).mp4' -# 或: qshell fput meijiaka-zy materials/4f2290dd81773eaada0a3a0cc8adf115.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(3).mp4' - -# 工地恶搞-恶搞开篇/5月16日(34).mp4 (8.01s) -# qshell put meijiaka-zy materials/8021088c304e09ac93929660530d68ab.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(34).mp4' -# 或: qshell fput meijiaka-zy materials/8021088c304e09ac93929660530d68ab.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(34).mp4' - -# 工地恶搞-恶搞开篇/5月16日(35).mp4 (8.01s) -# qshell put meijiaka-zy materials/b25deff3d658d6b5e1f82715d5b32e6c.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(35).mp4' -# 或: qshell fput meijiaka-zy materials/b25deff3d658d6b5e1f82715d5b32e6c.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(35).mp4' - -# 工地恶搞-恶搞开篇/5月16日(7).mp4 (5.02s) -# qshell put meijiaka-zy materials/93e95bedaf905e63613d5971ecbde77d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(7).mp4' -# 或: qshell fput meijiaka-zy materials/93e95bedaf905e63613d5971ecbde77d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日(7).mp4' - -# 工地恶搞-恶搞开篇/5月16日.mp4 (8.01s) -# qshell put meijiaka-zy materials/17705678ad0757af9e70fd1ca4579882.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日.mp4' -# 或: qshell fput meijiaka-zy materials/17705678ad0757af9e70fd1ca4579882.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/工地恶搞-恶搞开篇/5月16日.mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(10).mp4 (4.02s) -# qshell put meijiaka-zy materials/6ea04c0905384386643a43ad3d8c62e8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(10).mp4' -# 或: qshell fput meijiaka-zy materials/6ea04c0905384386643a43ad3d8c62e8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(10).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(11).mp4 (4.02s) -# qshell put meijiaka-zy materials/c1c71478b19779df6d6231c76147c00e.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(11).mp4' -# 或: qshell fput meijiaka-zy materials/c1c71478b19779df6d6231c76147c00e.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(11).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(20).mp4 (4.02s) -# qshell put meijiaka-zy materials/fd03a112a4b9e7edc4534648d17b5cff.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(20).mp4' -# 或: qshell fput meijiaka-zy materials/fd03a112a4b9e7edc4534648d17b5cff.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(20).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(28).mp4 (7.34s) -# qshell put meijiaka-zy materials/70ea7edb5173568fa8079da9fe7da0bf.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(28).mp4' -# 或: qshell fput meijiaka-zy materials/70ea7edb5173568fa8079da9fe7da0bf.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(28).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(5).mp4 (5.04s) -# qshell put meijiaka-zy materials/688a3f761f110c7ce320a7a124baf191.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(5).mp4' -# 或: qshell fput meijiaka-zy materials/688a3f761f110c7ce320a7a124baf191.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(5).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(6).mp4 (4.11s) -# qshell put meijiaka-zy materials/0750b373b8d293020e593c0fb6ca973b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(6).mp4' -# 或: qshell fput meijiaka-zy materials/0750b373b8d293020e593c0fb6ca973b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(6).mp4' - -# 搞笑涂料施工-恶搞开篇/5月16日(9).mp4 (5.02s) -# qshell put meijiaka-zy materials/33a38a924ca3ee44ae651c452b742799.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(9).mp4' -# 或: qshell fput meijiaka-zy materials/33a38a924ca3ee44ae651c452b742799.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/搞笑涂料施工-恶搞开篇/5月16日(9).mp4' - -# 暴力拆除-恶搞开篇/5月16日(13).mp4 (4.25s) -# qshell put meijiaka-zy materials/2eaf1185874d48136e3fbc62e908d455.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(13).mp4' -# 或: qshell fput meijiaka-zy materials/2eaf1185874d48136e3fbc62e908d455.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(13).mp4' - -# 暴力拆除-恶搞开篇/5月16日(30).mp4 (7.62s) -# qshell put meijiaka-zy materials/d9fe52d52a13c5fcd15736f342f082fe.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(30).mp4' -# 或: qshell fput meijiaka-zy materials/d9fe52d52a13c5fcd15736f342f082fe.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(30).mp4' - -# 暴力拆除-恶搞开篇/5月16日(31).mp4 (6.78s) -# qshell put meijiaka-zy materials/c252875cd6948d0f38062cb07538194d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(31).mp4' -# 或: qshell fput meijiaka-zy materials/c252875cd6948d0f38062cb07538194d.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(31).mp4' - -# 暴力拆除-恶搞开篇/5月16日(42).mp4 (6.34s) -# qshell put meijiaka-zy materials/dd1cee83a3366ff11bd00df286193d0b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(42).mp4' -# 或: qshell fput meijiaka-zy materials/dd1cee83a3366ff11bd00df286193d0b.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/暴力拆除-恶搞开篇/5月16日(42).mp4' - -# 炫技-恶搞开篇/5月16日(15).mp4 (3.02s) -# qshell put meijiaka-zy materials/e36d1bceeebaadf20ccc5f8dfeb1ab97.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(15).mp4' -# 或: qshell fput meijiaka-zy materials/e36d1bceeebaadf20ccc5f8dfeb1ab97.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(15).mp4' - -# 炫技-恶搞开篇/5月16日(16).mp4 (3.55s) -# qshell put meijiaka-zy materials/a19a83b9a3b5f32daf154a46b457bb69.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(16).mp4' -# 或: qshell fput meijiaka-zy materials/a19a83b9a3b5f32daf154a46b457bb69.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(16).mp4' - -# 炫技-恶搞开篇/5月16日(17).mp4 (4.02s) -# qshell put meijiaka-zy materials/92baf7b9594e89c5f366fb77168a4879.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(17).mp4' -# 或: qshell fput meijiaka-zy materials/92baf7b9594e89c5f366fb77168a4879.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(17).mp4' - -# 炫技-恶搞开篇/5月16日(22).mp4 (5.04s) -# qshell put meijiaka-zy materials/a2c58cb2c6a1f2c1dec111f2fcefecc8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(22).mp4' -# 或: qshell fput meijiaka-zy materials/a2c58cb2c6a1f2c1dec111f2fcefecc8.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/炫技-恶搞开篇/5月16日(22).mp4' - -# 贴砖恶搞-恶搞开篇/5月16日(2).mp4 (8.01s) -# qshell put meijiaka-zy materials/62d4bc30cccf74a3300f40c3952470d3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(2).mp4' -# 或: qshell fput meijiaka-zy materials/62d4bc30cccf74a3300f40c3952470d3.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(2).mp4' - -# 贴砖恶搞-恶搞开篇/5月16日(29).mp4 (9.01s) -# qshell put meijiaka-zy materials/9a134ff2649212d5f33069c850df385f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(29).mp4' -# 或: qshell fput meijiaka-zy materials/9a134ff2649212d5f33069c850df385f.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(29).mp4' - -# 贴砖恶搞-恶搞开篇/5月16日(32).mp4 (8.03s) -# qshell put meijiaka-zy materials/00d6b249ce62c2553a23e3d93e460d91.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(32).mp4' -# 或: qshell fput meijiaka-zy materials/00d6b249ce62c2553a23e3d93e460d91.mp4 '/Users/0fun/Desktop/网红开篇/恶搞开篇/贴砖恶搞-恶搞开篇/5月16日(32).mp4' - -# 防水翻车漏水-施工翻车镜/5月16日(40).mp4 (8.01s) -# qshell put meijiaka-zy materials/73e70b1aacab4e4ddaa06f361ff1c07e.mp4 '/Users/0fun/Desktop/网红开篇/施工翻车镜/防水翻车漏水-施工翻车镜/5月16日(40).mp4' -# 或: qshell fput meijiaka-zy materials/73e70b1aacab4e4ddaa06f361ff1c07e.mp4 '/Users/0fun/Desktop/网红开篇/施工翻车镜/防水翻车漏水-施工翻车镜/5月16日(40).mp4' - -# 防水翻车漏水-施工翻车镜/5月16日(41).mp4 (7.5s) -# qshell put meijiaka-zy materials/6d770fb02e2bbb6000b8123fe5a9fb55.mp4 '/Users/0fun/Desktop/网红开篇/施工翻车镜/防水翻车漏水-施工翻车镜/5月16日(41).mp4' -# 或: qshell fput meijiaka-zy materials/6d770fb02e2bbb6000b8123fe5a9fb55.mp4 '/Users/0fun/Desktop/网红开篇/施工翻车镜/防水翻车漏水-施工翻车镜/5月16日(41).mp4' - diff --git a/tauri-app/AGENTS.md b/tauri-app/AGENTS.md index f0735da..5178aa2 100644 --- a/tauri-app/AGENTS.md +++ b/tauri-app/AGENTS.md @@ -9,7 +9,7 @@ **美家卡智影**(产品名)是一款基于 Tauri v2 + React 19 + TypeScript 的桌面端 AI 视频创作应用。 - **产品标识**: `cn.meijiaka.ai-video` -- **版本**: `1.8.2` +- **版本**: `1.9.1` - **窗口尺寸**: 1200×800,不可缩放(`resizable: false`) - **核心功能**: AI 脚本生成、AI 配音合成、视频生成、压制成片(FFmpeg)、项目本地持久化 @@ -22,7 +22,7 @@ | 桌面壳 | Tauri v2 (Rust) | | 状态管理 | Zustand 5 + Immer 11 | | 路由 | `react-router-dom` (BrowserRouter) + 自定义 `NavigationContext` 做页面切换 | -| 数据请求 | 自研智能路由客户端 (`src/api/client.ts`) + SWR | +| 数据请求 | HTTP 客户端 (`src/api/client.ts`) + SWR | | 测试 | Vitest 4 + jsdom + `@testing-library/react` | | 虚拟列表 | `@tanstack/react-virtual` | | 外部依赖 | FFmpeg(以 Tauri Sidecar 形式打包) | @@ -52,41 +52,49 @@ │ ├── main.tsx # React 挂载入口 │ ├── App.tsx # 根组件:导航上下文、主题、侧边栏布局 │ ├── api/ -│ │ ├── client.ts # 智能路由客户端(HTTP / IPC 自动选择) +│ │ ├── client.ts # HTTP 客户端(camelCase ↔ snake_case 自动转换) │ │ ├── types.ts # 通用 API 类型 │ │ └── modules/ # 按领域拆分的 API 模块 -│ │ ├── auth.ts -│ │ ├── script.ts # 脚本生成(含 SSE 流式接口) -│ │ ├── voice.ts -│ │ ├── video.ts -│ │ ├── videoComposite.ts # 压制成片(走 IPC) +│ │ ├── bgmMusic.ts +│ │ ├── config.ts │ │ ├── cover.ts -│ │ └── system.ts # 项目持久化 +│ │ ├── coverAvatar.ts +│ │ ├── localStorage.ts +│ │ ├── materials.ts +│ │ ├── points.ts +│ │ ├── script.ts # 脚本生成(含 SSE 流式接口) +│ │ ├── task.ts +│ │ ├── videoCompose.ts # 压制成片(走 IPC) +│ │ ├── videoComposite.ts +│ │ └── voice.ts │ ├── components/ # 可复用组件(PascalCase 文件夹) +│ │ ├── DatePicker/ +│ │ ├── ErrorBoundary/ │ │ ├── Layout/ │ │ ├── Modal/ +│ │ ├── PointsCard/ +│ │ ├── PricingModal/ +│ │ ├── ProgressModal/ +│ │ ├── RechargeModal/ +│ │ ├── ShotStats/ +│ │ ├── Slider/ │ │ ├── Toast/ -│ │ ├── ErrorBoundary/ -│ │ ├── VirtualShotList/ -│ │ └── ... +│ │ └── UpdateDialog/ │ ├── hooks/ # 自定义 React Hooks │ ├── pages/ # 页面级组件(PascalCase 文件夹) -│ │ ├── VideoCreation/ # 核心创作流程(脚本→音频→封面→合成) │ │ ├── ContentManagement/ -│ │ │ ├── VoiceClone/ -│ │ │ ├── DigitalHuman/ -│ │ │ └── MyWorks/ -│ │ ├── Settings/ +│ │ ├── Login/ │ │ ├── Profile/ -│ │ └── Login/ +│ │ ├── Settings/ +│ │ ├── VideoCreation/ # 核心创作流程(脚本→音频→封面→合成) +│ │ └── VideoGeneration/ │ ├── store/ # Zustand 状态管理 │ │ ├── authStore.ts │ │ ├── projectStore.ts # 项目数据(分镜、空镜、音频、封面等) │ │ ├── settingsStore.ts │ │ ├── uiStore.ts # Toast 等 UI 状态 │ │ ├── Provider.tsx -│ │ ├── index.ts -│ │ └── __tests__/ # Store 单元测试 +│ │ └── index.ts │ ├── styles/ │ │ ├── variables.css # CSS 变量(含主题变量) │ │ └── global.css # 全局样式 @@ -100,9 +108,12 @@ │ ├── icons/ # 应用图标 │ └── src/ │ ├── main.rs # 程序入口 -│ ├── lib.rs # Tauri Builder、Command 定义、Python 代理 +│ ├── lib.rs # Tauri Builder、Command 定义、公共类型 │ ├── ffmpeg_cmd.rs # FFmpeg 命令封装(拼接、音画合并、封面转视频) -│ └── persistence.rs # 项目本地文件读写 +│ ├── video_processing.rs # 压制成片业务逻辑 +│ ├── utils.rs # 通用工具 +│ ├── commands/ # Tauri IPC 命令(按领域拆分) +│ └── storage/ # 本地存储引擎(项目、认证、配置、头像等) └── public/ # 静态资源 ``` @@ -153,7 +164,7 @@ npm run test:coverage ### 注释语言 - 项目内**统一使用中文注释**。 -- 关键架构决策需在代码中以多行注释说明(参考 `src/api/client.ts` 顶部的“混合模式智能路由”注释)。 +- 关键架构决策需在代码中以多行注释说明(参考 `src/api/client.ts` 顶部的 HTTP 客户端与认证处理注释)。 ### TypeScript 配置 @@ -171,7 +182,7 @@ npm run test:coverage 1. **判断是否需要本地能力**(FFmpeg、文件系统、系统调用)。 2. **不需要** → 直接在 `src/api/modules/` 使用 `client.get/post/put/delete` 调用 Python HTTP API。 -3. **需要** → 将 endpoint 加入 `src/api/client.ts` 的 `RUST_IPC_APIS` 集合,并在 `src-tauri/src/lib.rs` 中实现对应的 `#[tauri::command]` 处理器。 +3. **需要** → 在 `src/api/modules/` 中通过 `@tauri-apps/api/core` 的 `invoke` 调用 Rust 命令,并在 `src-tauri/src/commands/` 或 `lib.rs` 中实现对应的 `#[tauri::command]` 处理器。 --- @@ -186,7 +197,6 @@ npm run test:coverage ### 测试文件位置 - 全局 setup: `src/__tests__/setup.ts` -- Store 测试: `src/store/__tests__/*.test.tsx` - 组件/页面测试: 建议放在被测文件同目录或 `__tests__` 子目录中 ### Mock 策略 @@ -215,21 +225,24 @@ npm run test:ui ### CSP 配置 -`src-tauri/tauri.conf.json` 中已配置 Content Security Policy: +`src-tauri/tauri.conf.json` 中已配置 Content Security Policy,关键策略包括: - `default-src`: `'self'` -- `connect-src`: `'self' http://localhost:8080 http://127.0.0.1:8080` -- `img-src` / `media-src`: 允许 `http://localhost:8080` 及 `blob:`、`data:` +- `script-src`: `'self'` +- `style-src`: `'self' 'unsafe-inline'` +- `connect-src`: `'self' https: ws://localhost:* wss://localhost:* ipc://localhost ipc://localhost/* http://ipc.localhost` +- `img-src` / `media-src`: 允许 `https:`、`blob:`、`data:`、`asset:` 及 `http://asset.localhost` +- `font-src`: 允许 `asset:` 及 `http://asset.localhost` ### 外部二进制 -- FFmpeg 作为 **sidecar** 打包(`bundle.externalBin: ["binaries/ffmpeg"]`)。 +- FFmpeg / ffprobe 作为 **sidecar** 打包(`bundle.externalBin: ["binaries/ffmpeg", "binaries/ffprobe"]`)。 - Rust 层通过 `tauri_plugin_shell` 的 `sidecar("ffmpeg")` 调用。 - 合成过程中会解析 FFmpeg stderr 输出中的 `time=` 字段,并通过 Tauri Event (`ffmpeg-progress`) 向前端发送进度。 ### 项目文件存储路径 -- **项目持久化文件**: `{app_config_dir}/current_project.json`(由 `persistence.rs` 管理)。 +- **项目持久化文件**: `{app_config_dir}/current_project.json`(由 `src-tauri/src/storage/project.rs` 管理)。 - **合成临时文件**: `{document_dir}/Meijiaka/Projects/`(由 `lib.rs` 中的 `get_project_dir` 管理)。 ### 认证状态 diff --git a/tauri-app/package.json b/tauri-app/package.json index cb76cee..a35143c 100644 --- a/tauri-app/package.json +++ b/tauri-app/package.json @@ -1,7 +1,7 @@ { "name": "tauri-app", "private": true, - "version": "1.8.3", + "version": "1.9.1", "type": "module", "scripts": { "dev": "vite", diff --git a/tauri-app/src-tauri/Cargo.lock b/tauri-app/src-tauri/Cargo.lock index 2212586..e09a0c5 100644 --- a/tauri-app/src-tauri/Cargo.lock +++ b/tauri-app/src-tauri/Cargo.lock @@ -4219,7 +4219,7 @@ dependencies = [ [[package]] name = "tauri-app" -version = "1.8.3" +version = "1.9.1" dependencies = [ "base64 0.22.1", "chrono", diff --git a/tauri-app/src-tauri/Cargo.toml b/tauri-app/src-tauri/Cargo.toml index 20de024..1149794 100644 --- a/tauri-app/src-tauri/Cargo.toml +++ b/tauri-app/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-app" -version = "1.8.3" +version = "1.9.1" description = "美家卡智影 - AI 视频创作桌面应用" authors = ["美家卡科技"] edition = "2021" diff --git a/tauri-app/src-tauri/capabilities/default.json b/tauri-app/src-tauri/capabilities/default.json index 296fbe8..89affaa 100644 --- a/tauri-app/src-tauri/capabilities/default.json +++ b/tauri-app/src-tauri/capabilities/default.json @@ -51,8 +51,12 @@ }, "dialog:default", "dialog:allow-open", + "dialog:allow-confirm", "core:window:allow-show", "core:window:allow-set-focus", + "core:window:allow-close", + "core:window:allow-destroy", + "core:window:allow-unminimize", "updater:default", "process:allow-restart" ] diff --git a/tauri-app/src-tauri/tauri.conf.json b/tauri-app/src-tauri/tauri.conf.json index 5debffc..347c02d 100644 --- a/tauri-app/src-tauri/tauri.conf.json +++ b/tauri-app/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "美家卡智影", - "version": "1.8.3", + "version": "1.9.1", "identifier": "cn.meijiaka.ai-zy", "build": { "beforeDevCommand": "npm run dev", diff --git a/tauri-app/src/App.tsx b/tauri-app/src/App.tsx index ee0e449..545db3d 100644 --- a/tauri-app/src/App.tsx +++ b/tauri-app/src/App.tsx @@ -23,6 +23,7 @@ import { initProjectStore } from './store/projectStore'; import { loadAppConfig } from './api/modules/config'; import { setApiBaseUrl } from './api/client'; import { NavigationContext } from './contexts/NavigationContext'; +import { useCloseGuard } from './hooks/useCloseGuard'; import './App.css'; @@ -63,7 +64,13 @@ function renderPage(page: PageType): React.ReactNode { * 主应用组件 */ function App() { + // 全局窗口关闭守卫:有未完成任务时提示用户 + useCloseGuard(); + const { isAuthenticated, logout, loadFromStorage, showKickModal, kickMessage, closeKickModal } = useAuthStore(); + const handleKickClose = async () => { + await closeKickModal(); + }; const [currentPage, setCurrentPage] = useState('video-creation'); const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); const [appEnvironment, setAppEnvironment] = useState('production'); @@ -142,8 +149,8 @@ function App() { title={kickMessage || '当前账号在其他设备登录,即将退出'} confirmText="确认" confirmButtonType="primary" - onConfirm={closeKickModal} - onCancel={closeKickModal} + onConfirm={handleKickClose} + onCancel={handleKickClose} /> {/* 主应用层 - 始终渲染但可能被覆盖 */} diff --git a/tauri-app/src/api/client.ts b/tauri-app/src/api/client.ts index af949b4..007a42b 100644 --- a/tauri-app/src/api/client.ts +++ b/tauri-app/src/api/client.ts @@ -95,17 +95,36 @@ export function clearAuthCache(): void { // ═══════════════════════════════════════════════════════════════ let isRefreshing = false; -let refreshSubscribers: Array<(accessToken: string) => void> = []; +let refreshSubscribers: Array<(accessToken: string, err?: Error) => void> = []; function onRefreshed(accessToken: string) { refreshSubscribers.forEach(cb => cb(accessToken)); refreshSubscribers = []; } -function addRefreshSubscriber(cb: (accessToken: string) => void) { +function onRefreshFailed(err: Error) { + refreshSubscribers.forEach(cb => cb('', err)); + refreshSubscribers = []; +} + +function addRefreshSubscriber(cb: (accessToken: string, err?: Error) => void) { refreshSubscribers.push(cb); } +/** + * base64url 解码(JWT payload 使用 base64url,不是标准 base64) + */ +function base64UrlDecode(str: string): string { + const padding = '='.repeat((4 - (str.length % 4)) % 4); + const base64 = str.replace(/-/g, '+').replace(/_/g, '/') + padding; + const binary = atob(base64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return new TextDecoder('utf-8', { fatal: true }).decode(bytes); +} + /** * 检查 JWT 是否即将过期 * @param token JWT Token @@ -113,7 +132,7 @@ function addRefreshSubscriber(cb: (accessToken: string) => void) { */ function isTokenExpired(token: string, bufferSeconds = 300): boolean { try { - const payload = JSON.parse(atob(token.split('.')[1])); + const payload = JSON.parse(base64UrlDecode(token.split('.')[1])); if (!payload.exp) {return true;} return payload.exp * 1000 < Date.now() + bufferSeconds * 1000; } catch { @@ -218,14 +237,24 @@ async function httpRequest( if (newToken) { token = newToken; onRefreshed(newToken); + } else { + const err = new Error('Token 刷新失败'); + onRefreshFailed(err); + throw err; } + } catch (e) { + const err = e instanceof Error ? e : new Error('Token 刷新失败'); + onRefreshFailed(err); + throw err; } finally { isRefreshing = false; } } else { // 等待其他请求刷新完成 - token = await new Promise((resolve) => { - addRefreshSubscriber((newToken) => resolve(newToken)); + token = await new Promise((resolve, reject) => { + addRefreshSubscriber((newToken, err) => { + if (err) { reject(err); } else { resolve(newToken); } + }); }); } } @@ -274,15 +303,22 @@ async function httpRequest( onRefreshed(newToken); return httpRequest(method, path, body, { ...options, _retry: true }); } + const authError = new Error('认证已失效'); + onRefreshFailed(authError); + throw authError; + } catch (e) { + const authError = e instanceof Error ? e : new Error('认证已失效'); + onRefreshFailed(authError); + throw authError; } finally { isRefreshing = false; - // 无论成功失败,都唤醒等待中的 subscriber,避免请求永远挂死 - onRefreshed(cachedAuth?.accessToken || ''); } } else { // 等待刷新完成后重试 - await new Promise((resolve) => { - addRefreshSubscriber(() => resolve()); + await new Promise((resolve, reject) => { + addRefreshSubscriber((_, err) => { + if (err) { reject(err); } else { resolve(); } + }); }); return httpRequest(method, path, body, { ...options, _retry: true }); } @@ -290,7 +326,7 @@ async function httpRequest( if (!response.ok) { const errorText = await response.text().catch(() => response.statusText); - throw new Error(extractErrorMessage(errorText, `HTTP ${response.status}: ${response.statusText}`)); + throw createRequestError(errorText, `HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); @@ -310,20 +346,22 @@ function parseResponse(raw: string | unknown): T { } /** - * 从错误响应中提取可读消息 + * 从错误响应中构造 Error 对象 * - * 后端错误统一返回 ApiErrorResponse 格式:{ code, message, detail } + * 后端错误统一返回 ApiErrorResponse 格式:{ code, message, error_code, detail } */ -function extractErrorMessage(responseText: string, fallbackStatus: string): string { +function createRequestError(responseText: string, fallbackStatus: string): Error { try { const errorData = JSON.parse(responseText); if (typeof errorData.message === 'string') { - return errorData.message; + const err = new Error(errorData.message) as Error & { errorCode?: string }; + err.errorCode = errorData.error_code; + return err; } } catch { // 解析失败,返回原始文本或默认状态信息 } - return responseText || fallbackStatus; + return new Error(responseText || fallbackStatus); } /** diff --git a/tauri-app/src/api/modules/points.ts b/tauri-app/src/api/modules/points.ts index 0a8cb79..cf7d2c9 100644 --- a/tauri-app/src/api/modules/points.ts +++ b/tauri-app/src/api/modules/points.ts @@ -179,7 +179,7 @@ export const pointsApi = { * 直接消费积分(前端/Rust 层业务扣费) * POST /points/consume * - * 余额不足时后端返回 402,调用方应捕获并引导充值。 + * 余额不足时后端返回 error_code='insufficient_points'(HTTP 402),调用方应通过 errorCode 识别。 */ consumePoints: async (payload: { points: number; diff --git a/tauri-app/src/api/modules/task.ts b/tauri-app/src/api/modules/task.ts index caba039..81be171 100644 --- a/tauri-app/src/api/modules/task.ts +++ b/tauri-app/src/api/modules/task.ts @@ -24,6 +24,7 @@ interface TaskStatusResult { total: number; result?: unknown; error?: string; + errorCode?: string; createdAt: string; } diff --git a/tauri-app/src/api/types.ts b/tauri-app/src/api/types.ts index 1d6d96b..5ff30df 100644 --- a/tauri-app/src/api/types.ts +++ b/tauri-app/src/api/types.ts @@ -7,6 +7,16 @@ export interface ApiResponse { message: string; } +/** + * 错误响应格式 + */ +export interface ApiErrorResponse { + code: number; + message: string; + errorCode?: string; + detail?: Record; +} + /** * 字幕打轴结果 */ diff --git a/tauri-app/src/hooks/useCloseGuard.ts b/tauri-app/src/hooks/useCloseGuard.ts new file mode 100644 index 0000000..3b2e42a --- /dev/null +++ b/tauri-app/src/hooks/useCloseGuard.ts @@ -0,0 +1,57 @@ +/** + * 窗口关闭守卫 Hook + * ================ + * + * 监听 Tauri 窗口关闭事件。当有未完成的操作(第三方调用或本地处理)时, + * 弹出确认框阻止误关闭;用户确认后再执行关闭。 + */ + +import { useEffect } from 'react'; +import { getCurrentWindow } from '@tauri-apps/api/window'; +import { confirm } from '@tauri-apps/plugin-dialog'; +import { hasPendingOperations } from '../utils/pendingOperations'; +import { isTauri } from '../utils/env'; + +export function useCloseGuard() { + useEffect(() => { + let unlisten: (() => void) | undefined; + // 用户确认关闭后,避免再次弹窗导致循环 + const closingRef = { current: false }; + + const setup = async () => { + if (!isTauri()) { + return; + } + const currentWindow = getCurrentWindow(); + unlisten = await currentWindow.onCloseRequested((event) => { + if (closingRef.current || !hasPendingOperations()) { + return; + } + // 同步阻止默认关闭行为,再异步询问用户 + event.preventDefault(); + + (async () => { + const confirmed = await confirm( + '当前有任务正在执行,关闭窗口会中断处理。已提交的任务和已扣除的积分不会回退,确定要关闭吗?', + { + title: '确认关闭', + kind: 'warning', + okLabel: '确定关闭', + cancelLabel: '取消', + }, + ); + if (confirmed) { + closingRef.current = true; + await currentWindow.close(); + } + })().catch(console.error); + }); + }; + + setup().catch(console.error); + + return () => { + unlisten?.(); + }; + }, []); +} diff --git a/tauri-app/src/hooks/usePendingOperation.ts b/tauri-app/src/hooks/usePendingOperation.ts new file mode 100644 index 0000000..efa1ab2 --- /dev/null +++ b/tauri-app/src/hooks/usePendingOperation.ts @@ -0,0 +1,29 @@ +/** + * 自动包裹异步操作为“飞行中操作”的 Hook + * + * 用法: + * ```ts + * const handleGenerate = usePendingOperation(async () => { + * // 原有异步逻辑 + * }); + * ``` + */ + +import { useEffect, useMemo, useRef } from 'react'; +import { withPendingOperation } from '../utils/pendingOperations'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function usePendingOperation Promise>(fn: T): T { + const fnRef = useRef(fn); + useEffect(() => { + fnRef.current = fn; + }, [fn]); + + return useMemo( + () => + (async (...args: Parameters) => { + return withPendingOperation(() => fnRef.current(...args)); + }) as T, + [], + ); +} diff --git a/tauri-app/src/hooks/usePointsCheck.tsx b/tauri-app/src/hooks/usePointsCheck.tsx index 64edec8..6de814d 100644 --- a/tauri-app/src/hooks/usePointsCheck.tsx +++ b/tauri-app/src/hooks/usePointsCheck.tsx @@ -28,6 +28,8 @@ import { useState, useCallback } from 'react'; import { usePointStore } from '../store'; import ConfirmModal from '../components/Modal/ConfirmModal'; import RechargeModal from '../components/RechargeModal/RechargeModal'; +import { isInsufficientPointsError } from '../utils/errorMessage'; + export function usePointsCheck() { const [showPointsModal, setShowPointsModal] = useState(false); @@ -46,7 +48,7 @@ export function usePointsCheck() { * @returns true=余额足够,false=不足并已弹窗 */ const checkBalance = useCallback( - async (points: number | { min: number; max: number }, _bizName: string, strict: boolean = true): Promise => { + async (points: number | { min: number; max: number }, strict: boolean = true): Promise => { await fetchBalance(); const balance = usePointStore.getState().balance; const maxPoints = typeof points === 'number' ? points : points.max; @@ -81,10 +83,9 @@ export function usePointsCheck() { * @returns true=已识别为积分不足并弹窗,false=不是积分不足 */ const handleError = useCallback( - (error: unknown, _bizName: string, _requiredPoints?: number): boolean => { - const msg = error instanceof Error ? error.message : String(error); - if (msg.includes('402') || msg.includes('积分不足')) { - setModalDescription(`预计消耗 ${_requiredPoints || '?'} 积分`); + (error: unknown, requiredPoints?: number): boolean => { + if (isInsufficientPointsError(error)) { + setModalDescription(`预计消耗 ${requiredPoints || '?'} 积分`); setShowPointsModal(true); return true; } diff --git a/tauri-app/src/pages/ContentManagement/VoiceMaterialLibrary.tsx b/tauri-app/src/pages/ContentManagement/VoiceMaterialLibrary.tsx index 0bfbb4e..cbcd279 100644 --- a/tauri-app/src/pages/ContentManagement/VoiceMaterialLibrary.tsx +++ b/tauri-app/src/pages/ContentManagement/VoiceMaterialLibrary.tsx @@ -15,6 +15,8 @@ import * as voiceApi from '../../api/modules/voice'; import Modal from '../../components/Modal/Modal'; import ConfirmModal from '../../components/Modal/ConfirmModal'; import RechargeModal from '../../components/RechargeModal/RechargeModal'; +import { isInsufficientPointsError } from '../../utils/errorMessage'; + import './ContentManagement.css'; export default function VoiceMaterialLibrary() { @@ -261,12 +263,12 @@ export default function VoiceMaterialLibrary() { progress.success('复刻成功', 200); } catch (err) { console.error('[VoiceMaterialLibrary] handleUpload catch:', err, '类型:', typeof err, '是Error?', err instanceof Error); - const msg = err instanceof Error ? err.message : '上传失败'; - if (msg.includes('402') || msg.includes('积分不足')) { + if (isInsufficientPointsError(err)) { setShowPointsModal(true); progress.hide(); return; } + const msg = err instanceof Error ? err.message : '上传失败'; progress.error(msg); } diff --git a/tauri-app/src/pages/Settings/Settings.tsx b/tauri-app/src/pages/Settings/Settings.tsx index 9bdfb06..f6e7807 100644 --- a/tauri-app/src/pages/Settings/Settings.tsx +++ b/tauri-app/src/pages/Settings/Settings.tsx @@ -208,7 +208,12 @@ export default function Settings() { } toast.success('配置已保存,应用即将重启'); - setTimeout(() => { invoke('restart_app'); }, 800); + setTimeout(() => { + invoke('restart_app').catch((err) => { + console.error('[Settings] 重启应用失败:', err); + toast.error('重启应用失败'); + }); + }, 800); } catch { toast.error('保存配置失败'); } diff --git a/tauri-app/src/pages/VideoCreation/CoverDesign.tsx b/tauri-app/src/pages/VideoCreation/CoverDesign.tsx index 9a18a76..85108e7 100644 --- a/tauri-app/src/pages/VideoCreation/CoverDesign.tsx +++ b/tauri-app/src/pages/VideoCreation/CoverDesign.tsx @@ -25,12 +25,11 @@ import { scriptApi } from '../../api/modules/script'; import { coverApi, CoverBackground } from '../../api/modules/cover'; import { pointsApi } from '../../api/modules/points'; import { usePointStore, useAuthStore } from '../../store'; -import RechargeModal from '../../components/RechargeModal/RechargeModal'; -import ConfirmModal from '../../components/Modal/ConfirmModal'; import Modal from '../../components/Modal/Modal'; import { toast } from '../../store/uiStore'; import { getFriendlyErrorMessage } from '../../utils/errorMessage'; import { usePointsCheck } from '../../hooks/usePointsCheck'; +import { usePendingOperation } from '../../hooks/usePendingOperation'; import './CoverDesign.css'; interface BgImage { @@ -89,10 +88,6 @@ export default function CoverDesign() { const [isGeneratingMainTitle, setIsGeneratingMainTitle] = useState(false); const [isGeneratingSubTitle, setIsGeneratingSubTitle] = useState(false); const [isDesigning, setIsDesigning] = useState(false); - const [showPointsModal, setShowPointsModal] = useState(false); - const showRechargeModal = usePointStore(state => state.showRechargeModal); - const setShowRechargeModal = usePointStore(state => state.setShowRechargeModal); - const fetchBalance = usePointStore(state => state.fetchBalance); // 弹窗状态 const [bgModalOpen, setBgModalOpen] = useState(false); @@ -107,10 +102,10 @@ export default function CoverDesign() { const { canvasRef, initCanvas, renderCover, exportPng } = useCoverFabric(); - const { checkBalance } = usePointsCheck(); + const { checkBalance, handleError, PointsModal } = usePointsCheck(); // 智能生成标题 - const handleGenerateTitle = async (titleType: 'main' | 'sub') => { + const handleGenerateTitle = usePendingOperation(async (titleType: 'main' | 'sub') => { const projectStore = useProjectStore.getState(); const utterances = projectStore.subtitleAlignment?.utterances; if (!utterances || utterances.length === 0) { @@ -118,7 +113,7 @@ export default function CoverDesign() { return; } const titlePoints = usePointStore.getState().getRule('title')?.points || 1; - const canProceed = await checkBalance(titlePoints, '标题生成', true); + const canProceed = await checkBalance(titlePoints, true); if (!canProceed) {return;} const scriptContent = utterances.map(u => u.text).join('\n'); @@ -142,11 +137,10 @@ export default function CoverDesign() { })); toast.success(`${titleType === 'main' ? '主标题' : '副标题'}生成成功`); } catch (e) { - const msg = getFriendlyErrorMessage(e, '标题生成失败,请稍后重试'); - if (msg.includes('积分不足')) { - setShowPointsModal(true); + if (handleError(e, titlePoints)) { return; } + const msg = getFriendlyErrorMessage(e, '标题生成失败,请稍后重试'); toast.error(msg); } finally { if (titleType === 'main') { @@ -155,11 +149,12 @@ export default function CoverDesign() { setIsGeneratingSubTitle(false); } } - }; + }); // 加载背景图 — 系统图库 + 本地上传 const localBgRef = useRef(null); const blobUrlsRef = useRef>(new Set()); + const designLockRef = useRef(false); const [bgList, setBgList] = useState([]); useEffect(() => { @@ -246,22 +241,6 @@ export default function CoverDesign() { })); }, [coverConfig]); - // 背景图/形象变化时自动保存 coverConfig(防抖,只监听视觉素材) - useEffect(() => { - if (!projectId) {return;} - const timer = setTimeout(() => { - useProjectStore.getState().setCoverConfig({ - template: config.template, - backgroundImage: config.backgroundImage, - mainTitle: config.mainTitle, - subtitle: config.subtitle, - avatarImage: config.avatarImage, - }); - }, 300); - return () => clearTimeout(timer); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [config.backgroundImage, config.avatarImage, projectId]); - // 探测视频分辨率(优先从成品视频,其次从人物形象素材) useEffect(() => { const detect = async () => { @@ -301,20 +280,22 @@ export default function CoverDesign() { }, [config, renderCover, videoResolution]); // 生成封面图 - const handleGenerate = async () => { - if (!projectId) {return;} - if (!config.mainTitle.trim()) {return;} - - const coverPoints = usePointStore.getState().getRule('cover_design')?.points || 2; - await fetchBalance(); - const currentBalance = usePointStore.getState().balance; - if (currentBalance < coverPoints) { - setShowPointsModal(true); + const handleGenerate = usePendingOperation(async () => { + // 请求去重锁:防止快速双击发起多次封面生成 + if (designLockRef.current) { return; } - setShowPointsModal(false); + designLockRef.current = true; - setIsDesigning(true); + try { + if (!projectId) {return;} + if (!config.mainTitle.trim()) {return;} + + const coverPoints = usePointStore.getState().getRule('cover_design')?.points || 2; + const canProceed = await checkBalance(coverPoints); + if (!canProceed) {return;} + + setIsDesigning(true); useProgressStore.getState().show('封面设计'); try { @@ -361,8 +342,8 @@ export default function CoverDesign() { }); await usePointStore.getState().fetchBalance(); - setCoverPath(result.data); - setCoverConfig({ + await setCoverPath(result.data); + await setCoverConfig({ template: config.template, backgroundImage: config.backgroundImage, mainTitle: config.mainTitle.trim(), @@ -374,18 +355,20 @@ export default function CoverDesign() { useProjectStore.getState().markStepsDirty(5); useProgressStore.getState().success('封面设计完成', coverDesignPoints); } catch (error: unknown) { - const message = (error instanceof Error ? error.message : String(error)) || '封面设计失败'; console.error('封面设计失败:', error); - if (message.includes('402') || message.includes('积分不足')) { + if (handleError(error, coverPoints)) { useProgressStore.getState().hide(); - setShowPointsModal(true); - } else { - useProgressStore.getState().error(message); + return; } + const message = (error instanceof Error ? error.message : String(error)) || '封面设计失败'; + useProgressStore.getState().error(message); } finally { setIsDesigning(false); } - }; + } finally { + designLockRef.current = false; + } + }); // 封面形象库 const { coverAvatars, loadCoverAvatars } = useCoverAvatarStore(); @@ -403,29 +386,7 @@ export default function CoverDesign() { 上游数据已更新,当前封面可能与最新内容不匹配,建议重新设计 )} - { - setShowPointsModal(false); - setShowRechargeModal(true); - }} - onCancel={() => setShowPointsModal(false)} - onClose={() => setShowPointsModal(false)} - /> - setShowRechargeModal(false)} - onRechargeSuccess={() => { - fetchBalance(); - setShowPointsModal(false); - }} - /> + {/* 背景图弹窗 */} ([]); @@ -141,7 +143,9 @@ export default function ScriptCreation() { return status.result; } if (status.status === 'failed') { - throw new Error(status.error || '任务执行失败'); + const err = new Error(status.error || '任务执行失败') as Error & { errorCode?: string }; + err.errorCode = status.errorCode ?? undefined; + throw err; } // pending / running / waiting 继续轮询 await new Promise(r => setTimeout(r, interval)); @@ -153,23 +157,27 @@ export default function ScriptCreation() { /** * 执行生成脚本(异步任务 + 轮询) */ - const doGenerate = async () => { - if (!selectedCategory || !selectedFilename) { - toast.warning('请选择创作主题'); - return; - } - - // 前置积分检查:脚本生成 - const scriptPoints = usePointStore.getState().getRule('script')?.points || 5; - const ok = await checkBalance(scriptPoints, '脚本生成'); - if (!ok) {return;} - + const doGenerate = usePendingOperation(async () => { // 请求去重锁:防止网络延迟期间快速点击发起多个请求 if (requestLock.current) { return; } requestLock.current = true; + if (!selectedCategory || !selectedFilename) { + toast.warning('请选择创作主题'); + requestLock.current = false; + return; + } + + // 前置积分检查:脚本生成 + const scriptPoints = usePointStore.getState().getRule('script')?.points || 5; + const ok = await checkBalance(scriptPoints); + if (!ok) { + requestLock.current = false; + return; + } + setGenerating(true); const progress = useProgressStore.getState(); progress.show('脚本生成'); @@ -223,7 +231,7 @@ export default function ScriptCreation() { setTopic(title); } } catch (error) { - if (handleError(error, '脚本生成', 5)) { + if (handleError(error, 5)) { progress.hide(); return; } @@ -232,7 +240,7 @@ export default function ScriptCreation() { requestLock.current = false; setGenerating(false); } - }; + }); /** * 生成脚本入口(带确认弹窗) @@ -311,15 +319,24 @@ export default function ScriptCreation() { */ const { checkBalance, handleError, PointsModal } = usePointsCheck(); - const handlePolish = async ( + const handlePolish = usePendingOperation(async ( id: number, content: string, type: 'scene' | 'prompt' | 'voiceover' ) => { + // 请求去重锁:防止快速点击同一行润色发起多次请求 + if (polishLockRef.current) { + return; + } + polishLockRef.current = true; + // 前置积分检查:润色 const polishPoints = usePointStore.getState().getRule('polish')?.points || 1; - const ok = await checkBalance(polishPoints, type === 'voiceover' ? '文案润色' : '画面润色'); - if (!ok) {return;} + const ok = await checkBalance(polishPoints); + if (!ok) { + polishLockRef.current = false; + return; + } setPolishingState({ id, type }); try { @@ -331,13 +348,14 @@ export default function ScriptCreation() { const result = await scriptApi.polish(id, content, polishType, shotType); handleFieldChange(id, type, result); } catch (error) { - if (handleError(error, type === 'voiceover' ? '文案润色' : '画面润色', 1)) {return;} + if (handleError(error, 1)) {return;} console.error('润色失败:', error); toast.error('润色失败,请重试'); } finally { setPolishingState(null); + polishLockRef.current = false; } - }; + }); return (
diff --git a/tauri-app/src/pages/VideoCreation/SubtitleBurning.tsx b/tauri-app/src/pages/VideoCreation/SubtitleBurning.tsx index 9268b97..38e297a 100644 --- a/tauri-app/src/pages/VideoCreation/SubtitleBurning.tsx +++ b/tauri-app/src/pages/VideoCreation/SubtitleBurning.tsx @@ -14,8 +14,6 @@ import { getCurrentProjectId } from '../../api/modules/localStorage'; import { scriptApi } from '../../api/modules/script'; import { pointsApi } from '../../api/modules/points'; import { usePointStore, useAuthStore } from '../../store'; -import RechargeModal from '../../components/RechargeModal/RechargeModal'; -import ConfirmModal from '../../components/Modal/ConfirmModal'; import { useLocalVideo } from '../../hooks/useLocalVideo'; import { useCanvasSubtitleRenderer } from '../../hooks/useCanvasSubtitleRenderer'; @@ -24,6 +22,7 @@ import { useProgressStore } from '../../store/progressStore'; import { toast } from '../../store/uiStore'; import { getFriendlyErrorMessage } from '../../utils/errorMessage'; import { usePointsCheck } from '../../hooks/usePointsCheck'; +import { usePendingOperation } from '../../hooks/usePendingOperation'; import './SubtitleBurning.css'; @@ -79,16 +78,13 @@ export default function SubtitleBurning() { const [previewMode, setPreviewMode] = useState<'style' | 'result'>('style'); const [isGeneratingMainTitle, setIsGeneratingMainTitle] = useState(false); const [isGeneratingSubTitle, setIsGeneratingSubTitle] = useState(false); - const [showPointsModal, setShowPointsModal] = useState(false); // 视频原始分辨率(用于字幕缩放和 Canvas 预览基准) const [videoResolution, setVideoResolution] = useState<{ width: number; height: number } | null>(null); - const showRechargeModal = usePointStore(state => state.showRechargeModal); - const setShowRechargeModal = usePointStore(state => state.setShowRechargeModal); - const fetchBalance = usePointStore(state => state.fetchBalance); // 视频播放相关 const videoRef = useRef(null); const canvasRef = useRef(null); + const burnLockRef = useRef(false); // 预览用 const { videoUrl: loadedVideoUrl } = useLocalVideo(actualVideoUrl || actualVideoPath); @@ -122,10 +118,10 @@ export default function SubtitleBurning() { useProjectStore.setState({ subTitle: value }); }; - const { checkBalance } = usePointsCheck(); + const { checkBalance, handleError, PointsModal } = usePointsCheck(); // 智能生成标题 - const handleGenerateTitle = async (titleType: 'main' | 'sub') => { + const handleGenerateTitle = usePendingOperation(async (titleType: 'main' | 'sub') => { const utterances = alignment?.utterances; if (!utterances || utterances.length === 0) { toast.error('暂无脚本内容,请先生成脚本'); @@ -133,7 +129,7 @@ export default function SubtitleBurning() { } // 前置积分检查 const titlePoints = usePointStore.getState().getRule('title')?.points || 1; - const canProceed = await checkBalance(titlePoints, '标题生成', true); + const canProceed = await checkBalance(titlePoints, true); if (!canProceed) {return;} const scriptContent = utterances.map(u => u.text).join('\n'); @@ -158,11 +154,10 @@ export default function SubtitleBurning() { } toast.success(`${titleType === 'main' ? '大标题' : '小标题'}生成成功`); } catch (e) { - const msg = getFriendlyErrorMessage(e, '标题生成失败,请稍后重试'); - if (msg.includes('积分不足')) { - setShowPointsModal(true); + if (handleError(e, titlePoints)) { return; } + const msg = getFriendlyErrorMessage(e, '标题生成失败,请稍后重试'); toast.error(msg); } finally { if (titleType === 'main') { @@ -171,7 +166,7 @@ export default function SubtitleBurning() { setIsGeneratingSubTitle(false); } } - }; + }); const setMainTitlePreset = (value: string) => { useProjectStore.setState({ mainTitlePreset: value }); setPreviewMode('style'); @@ -349,31 +344,33 @@ export default function SubtitleBurning() { }, [isBurning, totalDurationSeconds]); // 压制字幕:单次压制全局字幕到成品视频 - const handleBurn = async () => { - if (!projectId) { - toast.error('项目ID不存在'); - return; - } - if (!actualVideoPath) { - toast.error('成品视频不存在'); - return; - } - if (!alignment?.utterances?.length) { - toast.error('请先完成字幕打轴'); + const handleBurn = usePendingOperation(async () => { + // 请求去重锁:防止快速双击发起多次字幕烧录 + if (burnLockRef.current) { return; } + burnLockRef.current = true; - // 积分预检:字幕烧录 - const subtitlePoints = usePointStore.getState().getRule('subtitle_burn')?.points || 2; - await fetchBalance(); - const currentBalance = usePointStore.getState().balance; - if (currentBalance < subtitlePoints) { - setShowPointsModal(true); - return; - } - setShowPointsModal(false); + try { + if (!projectId) { + toast.error('项目ID不存在'); + return; + } + if (!actualVideoPath) { + toast.error('成品视频不存在'); + return; + } + if (!alignment?.utterances?.length) { + toast.error('请先完成字幕打轴'); + return; + } - setIsBurning(true); + // 积分预检:字幕烧录 + const subtitlePoints = usePointStore.getState().getRule('subtitle_burn')?.points || 2; + const canProceed = await checkBalance(subtitlePoints); + if (!canProceed) {return;} + + setIsBurning(true); useProgressStore.getState().show('字幕烧录'); useProgressStore.getState().setProgress(0); @@ -477,13 +474,7 @@ export default function SubtitleBurning() { throw new Error(burnResult.message); } - // 7. 保存压制结果 - useProjectStore.setState({ burnedVideoPath: outputPath }); - await saveMetaToLocalFile({ burnedVideoPath: outputPath }); - useProjectStore.getState().clearStepDirty(4); - useProjectStore.getState().markStepsDirty(4); - - // 8. 扣费:字幕烧录(压制成功后才扣费) + // 7. 扣费:字幕烧录(压制成功后才扣费并保存结果) const subtitleBurnPoints = usePointStore.getState().getRule('subtitle_burn')?.points || 2; await pointsApi.consumePoints({ points: subtitleBurnPoints, @@ -493,21 +484,29 @@ export default function SubtitleBurning() { }); await usePointStore.getState().fetchBalance(); + // 8. 保存压制结果 + useProjectStore.setState({ burnedVideoPath: outputPath }); + await saveMetaToLocalFile({ burnedVideoPath: outputPath }); + useProjectStore.getState().clearStepDirty(4); + useProjectStore.getState().markStepsDirty(4); + useProgressStore.getState().success('字幕烧录完成', subtitleBurnPoints); } catch (error: unknown) { - const msg = error instanceof Error ? error.message : String(error); console.error('[SubtitleBurning] 压制失败:', error); - if (typeof msg === 'string' && (msg.includes('402') || msg.includes('积分不足'))) { + if (handleError(error, subtitlePoints)) { useProgressStore.getState().hide(); - setShowPointsModal(true); - } else { - useProgressStore.getState().error(msg || '压制失败'); - toast.error(msg || '压制失败'); + return; } + const msg = error instanceof Error ? error.message : String(error); + useProgressStore.getState().error(msg || '压制失败'); + toast.error(msg || '压制失败'); } finally { setIsBurning(false); } - }; + } finally { + burnLockRef.current = false; + } + }); return (
@@ -516,29 +515,7 @@ export default function SubtitleBurning() { 上游数据已更新,当前字幕压制结果可能不匹配,建议重新压制
)} - { - setShowPointsModal(false); - setShowRechargeModal(true); - }} - onCancel={() => setShowPointsModal(false)} - onClose={() => setShowPointsModal(false)} - /> - setShowRechargeModal(false)} - onRechargeSuccess={() => { - fetchBalance(); - setShowPointsModal(false); - }} - /> + {/* 左侧操作区 */}
{/* 大标题设置 */} diff --git a/tauri-app/src/pages/VideoCreation/VideoCompose.tsx b/tauri-app/src/pages/VideoCreation/VideoCompose.tsx index 677d387..e0c0222 100644 --- a/tauri-app/src/pages/VideoCreation/VideoCompose.tsx +++ b/tauri-app/src/pages/VideoCreation/VideoCompose.tsx @@ -14,9 +14,10 @@ import { useProgressStore } from '../../store/progressStore'; import { useLocalVideo } from '../../hooks/useLocalVideo'; import { toast } from '../../store/uiStore'; -import ConfirmModal from '../../components/Modal/ConfirmModal'; +import { usePointsCheck } from '../../hooks/usePointsCheck'; +import { usePendingOperation } from '../../hooks/usePendingOperation'; + import Modal from '../../components/Modal/Modal'; -import RechargeModal from '../../components/RechargeModal/RechargeModal'; import './VideoCreation.css'; import './VideoGeneration.css'; @@ -53,6 +54,7 @@ export default function VideoCompose() { const [bgmCategory, setBgmCategory] = useState('all'); const [previewId, setPreviewId] = useState(null); const audioRef = useRef(null); + const composeLockRef = useRef(false); const bgmMusicId = useProjectStore(state => state.bgmMusicId); const bgmMusicPath = useProjectStore(state => state.bgmMusicPath); const bgmMusicTitle = useProjectStore(state => state.bgmMusicTitle); @@ -128,11 +130,7 @@ export default function VideoCompose() { ? bgmList : bgmList.filter(item => item.category === bgmCategory); - // 积分不足弹窗 - const [showPointsModal, setShowPointsModal] = useState(false); - const showRechargeModal = usePointStore((state) => state.showRechargeModal); - const setShowRechargeModal = usePointStore((state) => state.setShowRechargeModal); - const fetchBalance = usePointStore((state) => state.fetchBalance); + const { checkBalance, handleError, PointsModal } = usePointsCheck(); // 同步 Store 中的 finalVideoPath 变化(如切换项目时) useEffect(() => { @@ -219,22 +217,24 @@ export default function VideoCompose() { }; }, [compositing, totalDurationSeconds]); - const handleStart = async () => { - if (videoPaths.length === 0) { + const handleStart = usePendingOperation(async () => { + // 请求去重锁:防止快速双击发起多次压制 + if (composeLockRef.current) { return; } + composeLockRef.current = true; - // 前置积分检查:压制成片 - const composePoints = usePointStore.getState().getRule('compose')?.points || 5; - await fetchBalance(); - const currentBalance = usePointStore.getState().balance; - if (currentBalance < composePoints) { - setShowPointsModal(true); - return; - } - setShowPointsModal(false); + try { + if (videoPaths.length === 0) { + return; + } - setCompositing(true); + // 前置积分检查:压制成片 + const composePoints = usePointStore.getState().getRule('compose')?.points || 5; + const canProceed = await checkBalance(composePoints); + if (!canProceed) {return;} + + setCompositing(true); setDone(false); setResultPath(''); useProgressStore.getState().show('压制成片'); @@ -300,12 +300,7 @@ export default function VideoCompose() { } } - setResultPath(result); - setFinalVideoPath(result); - setExportedAt(Date.now()); - useProgressStore.getState().setProgress(100); - - // 4. 扣费:压制成片 + // 3. 扣费:压制成片(先扣费,成功后再持久化结果) const composePoints = usePointStore.getState().getRule('compose')?.points || 5; try { await pointsApi.consumePoints({ @@ -315,29 +310,25 @@ export default function VideoCompose() { description: '压制成片', }); } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - // 回滚状态:未成功扣费视为合成未完成 setResultPath(''); - setFinalVideoPath(undefined); - setExportedAt(undefined); useProgressStore.getState().hide(); - setCompositing(false); - if (msg.includes('402') || msg.includes('积分不足')) { - setShowPointsModal(true); + if (handleError(err, composePoints)) { return; } toast.error('积分扣费失败,请重试'); return; } - // 5. 持久化最终路径和时长到 meta.json(无需二次复制) + // 4. 持久化最终路径、时长、封面到 meta.json + setResultPath(result); + await setFinalVideoPath(result); + await setExportedAt(Date.now()); await saveMetaToLocalFile({ - finalVideoPath: result, finalVideoDuration: totalDurationSeconds, - exportedAt: Date.now(), coverPath, }); + useProgressStore.getState().setProgress(100); useProjectStore.getState().clearStepDirty(6); setDone(true); useProgressStore.getState().success('压制成片完成', composePoints); @@ -347,7 +338,10 @@ export default function VideoCompose() { } finally { setCompositing(false); } - }; + } finally { + composeLockRef.current = false; + } + }); return ( <> @@ -675,24 +669,7 @@ export default function VideoCompose() {
- {/* 积分不足弹窗 */} - { setShowPointsModal(false); setShowRechargeModal(true); }} - onCancel={() => setShowPointsModal(false)} - onClose={() => setShowPointsModal(false)} - /> - setShowRechargeModal(false)} - onRechargeSuccess={() => { fetchBalance(); setShowPointsModal(false); }} - /> + {/* BGM 选择弹窗 */} (null); + const generateLockRef = useRef(false); // 台词字数不足弹窗 const [scriptCheckModal, setScriptCheckModal] = useState<{ @@ -285,19 +287,28 @@ export default function VoiceSynthesis() { // 注意:不在这里调用 progress.success,最终成功态由调用方 handleGenerate 统一设置 } catch (err) { console.error('[VoiceSynthesis] 打轴截取流程失败:', err); - progress.error(getFriendlyErrorMessage(err, '音频处理失败,请稍后重试')); + throw err; } }, [projectId, segments, updateSegment]); const { checkBalance, handleError, PointsModal } = usePointsCheck(); - const handleGenerate = useCallback(async () => { - if (!projectId) { toast.warning('请先创建项目'); return; } + const handleGenerate = usePendingOperation(useCallback(async () => { + // 请求去重锁:防止快速双击发起多次 TTS 请求 + if (generateLockRef.current) { + return; + } + generateLockRef.current = true; + + try { + if (!projectId) { toast.warning('请先创建项目'); return; } // 检查每个镜头的台词字数(剔除标点),当前语速下需满足 Math.ceil(4 * speed) 个字 const minChars = Math.ceil(4 * (speed || 1)); for (const seg of segments) { - if (!seg.voiceover?.trim()) continue; + if (!seg.voiceover?.trim()) { + continue; + } const pureChars = seg.voiceover.trim().replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '').length; if (pureChars < minChars) { setScriptCheckModal({ open: true, segId: seg.id, required: minChars, actual: pureChars }); @@ -331,7 +342,7 @@ export default function VoiceSynthesis() { if (!currentVoiceId) { toast.warning('请先选择音色'); setIsGenerating(false); return; } // 前置积分检查(宽松模式:余额为正即可执行,TTS 实际消耗不确定,允许欠费) - const ok = await checkBalance(estimatedTtsPoints, '配音合成', false); + const ok = await checkBalance(estimatedTtsPoints, false); if (!ok) {return;} const progress = useProgressStore.getState(); @@ -407,7 +418,7 @@ export default function VoiceSynthesis() { useProjectStore.getState().markStepsDirty(2); progress.success('配音合成完成', result.consumedPoints); } catch (err) { - if (handleError(err, '配音合成', estimatedTtsPoints.max)) { + if (handleError(err, estimatedTtsPoints.max)) { progress.hide(); return; } @@ -415,7 +426,10 @@ export default function VoiceSynthesis() { } finally { setIsGenerating(false); } - }, [projectId, segments, handleAlignAndClip, checkBalance, handleError, estimatedTtsPoints, clearStepDirty]); + } finally { + generateLockRef.current = false; + } + }, [projectId, segments, speed, handleAlignAndClip, checkBalance, handleError, estimatedTtsPoints, clearStepDirty])); const { navigate } = useNavigation(); @@ -475,7 +489,7 @@ export default function VoiceSynthesis() { {activeVoiceTab === 'preset' && (
{presetVoices.map(v => ( -
{ setSelectedVoiceId(v.voiceId); saveMetaToLocalFile({ selectedVoiceId: v.voiceId }); }}> +
{ setSelectedVoiceId(v.voiceId); saveMetaToLocalFile({ selectedVoiceId: v.voiceId }).catch((err) => console.error('保存音色选择失败:', err)); }}>
@@ -504,7 +518,7 @@ export default function VoiceSynthesis() {
) : ( voiceMaterials.filter(m => m.status === 'ready').map(m => ( -
{ setSelectedVoiceId(m.voiceId); saveMetaToLocalFile({ selectedVoiceId: m.voiceId }); }}> +
{ setSelectedVoiceId(m.voiceId); saveMetaToLocalFile({ selectedVoiceId: m.voiceId }).catch((err) => console.error('保存音色选择失败:', err)); }}>
@@ -540,7 +554,7 @@ export default function VoiceSynthesis() { max={20} step={1} value={Math.round(speed * 10)} - onChange={e => { const v = parseInt(e.target.value) / 10; setSpeed(v); saveMetaToLocalFile({ voiceSpeed: v }); }} + onChange={e => { const v = parseInt(e.target.value) / 10; setSpeed(v); saveMetaToLocalFile({ voiceSpeed: v }).catch((err) => console.error('保存语速失败:', err)); }} style={{ '--slider-percent': `${((Math.round(speed * 10) - 5) / 15) * 100}%` } as React.CSSProperties} /> 2.0x @@ -562,7 +576,7 @@ export default function VoiceSynthesis() { max={5} step={1} value={volume + 1} - onChange={e => { const v = parseInt(e.target.value) - 1; setVolume(v); saveMetaToLocalFile({ voiceVolume: v }); }} + onChange={e => { const v = parseInt(e.target.value) - 1; setVolume(v); saveMetaToLocalFile({ voiceVolume: v }).catch((err) => console.error('保存音量失败:', err)); }} style={{ '--slider-percent': `${((volume) / 4) * 100}%` } as React.CSSProperties} /> 5 diff --git a/tauri-app/src/pages/VideoGeneration/hooks/useVideoGeneration.ts b/tauri-app/src/pages/VideoGeneration/hooks/useVideoGeneration.ts index 9a78e5a..1d9f189 100644 --- a/tauri-app/src/pages/VideoGeneration/hooks/useVideoGeneration.ts +++ b/tauri-app/src/pages/VideoGeneration/hooks/useVideoGeneration.ts @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import { invoke } from '@tauri-apps/api/core'; import { getLocalFileUrl } from '../../../utils/fileUrl'; import { getFriendlyErrorMessage } from '../../../utils/errorMessage'; @@ -7,6 +7,7 @@ import { useProjectStore, saveMetaToLocalFile } from '../../../store'; import { useProgressStore } from '../../../store/progressStore'; import { usePointStore } from '../../../store'; import { useAuthStore } from '../../../store'; +import { usePendingOperation } from '../../../hooks/usePendingOperation'; import { concatVideoClips, @@ -23,11 +24,10 @@ import type { ScriptShot } from '../../../types/project'; export interface UseVideoGenerationParams { selectedAvatarMaterial: { id: string; name: string; duration: number; path: string } | null; materialMatchMap: Record; - estimatedVideoPoints: number; videoMultiplier: number; onSuccess: () => void; - checkBalance: (points: number, bizName: string, strict?: boolean) => Promise; - handleError: (error: unknown, bizName: string, requiredPoints?: number) => boolean; + checkBalance: (points: number, strict?: boolean) => Promise; + handleError: (error: unknown, requiredPoints?: number) => boolean; } export interface UseVideoGenerationResult { @@ -45,13 +45,13 @@ export interface UseVideoGenerationResult { export function useVideoGeneration({ selectedAvatarMaterial, materialMatchMap, - estimatedVideoPoints, videoMultiplier, onSuccess, checkBalance, handleError, }: UseVideoGenerationParams): UseVideoGenerationResult { const [isComposing, setIsComposing] = useState(false); + const generateLockRef = useRef(false); const segments = useProjectStore((state) => state.segments); const dubbingAudioPath = useProjectStore((state) => state.dubbingAudioPath); const updateSegment = useProjectStore((state) => state.updateSegment); @@ -59,16 +59,23 @@ export function useVideoGeneration({ const fetchBalance = usePointStore((state) => state.fetchBalance); - const handleGenerate = async () => { - if (!selectedAvatarMaterial) { - toast.warning('请选择人物出镜素材'); + const handleGenerate = usePendingOperation(async () => { + // 请求去重锁:防止快速双击发起多次视频生成 + if (generateLockRef.current) { return; } + generateLockRef.current = true; - if (!projectId) { - toast.error('项目ID不存在,请保存项目后再试'); - return; - } + try { + if (!selectedAvatarMaterial) { + toast.warning('请选择人物出镜素材'); + return; + } + + if (!projectId) { + toast.error('项目ID不存在,请保存项目后再试'); + return; + } const shots = segments; if (shots.length === 0) { @@ -91,26 +98,63 @@ export function useVideoGeneration({ return; } - // 积分预检 + const avatarDuration = selectedAvatarMaterial.duration; + const segmentShots = shots.filter((s: ScriptShot) => s.type === 'segment'); + + if (!dubbingAudioPath) { + toast.warning('缺少配音音频文件,请回到第2步重新生成音频'); + return; + } + + // 计算所有分镜规划总时长(提交任务时需要) const totalPlannedDuration = shots.reduce((sum: number, shot: ScriptShot) => { const durStr = typeof shot.duration === 'string' ? shot.duration : '5s'; return sum + parseFloat(durStr.replace(/[^0-9.]/g, '') || '0'); }, 0); + // 计算实际应扣积分:优先使用已保存的配音音频时长 + const storeAudioDuration = useProjectStore.getState().dubbingAudioDuration; + let totalAudioDuration: number; + if (storeAudioDuration && storeAudioDuration > 0) { + totalAudioDuration = storeAudioDuration; + } else { + const audioUrl = await getLocalFileUrl(dubbingAudioPath); + totalAudioDuration = await new Promise((resolve, reject) => { + const audio = new Audio(audioUrl); + const timeoutId = setTimeout(() => { + reject(new Error('读取音频时长超时,请检查音频文件')); + }, 15000); + audio.onloadedmetadata = () => { + clearTimeout(timeoutId); + resolve(audio.duration); + }; + audio.onerror = () => { + clearTimeout(timeoutId); + reject(new Error('读取音频时长失败')); + }; + }); + } + const baseVideoPoints = Math.ceil(totalAudioDuration) * videoMultiplier; + // 系统素材额外收费:每个空镜使用的系统素材额外 2 积分 + const systemMaterialCount = shots.filter((s: ScriptShot) => { + if (s.type !== 'empty_shot') {return false;} + const matched = materialMatchMap[String(s.id)]; + return matched && (matched.url.startsWith('http://') || matched.url.startsWith('https://')); + }).length; + const actualVideoPoints = baseVideoPoints + systemMaterialCount * 2; + setIsComposing(true); const progress = useProgressStore.getState(); try { - // 前置积分检查(严格模式) - const canProceed = await checkBalance(estimatedVideoPoints, '视频生成', true); + // 前置积分检查(严格模式,用实际应扣金额) + const canProceed = await checkBalance(actualVideoPoints, true); if (!canProceed) { setIsComposing(false); return; } progress.show('视频生成'); - const avatarDuration = selectedAvatarMaterial.duration; - const segmentShots = shots.filter((s: ScriptShot) => s.type === 'segment'); // ========== Step 1: 对每个 segment 提交视频生成任务 ========== for (let i = 0; i < segmentShots.length; i++) { @@ -183,6 +227,18 @@ export function useVideoGeneration({ const currentSegments = useProjectStore.getState().segments; await localProjectApi.saveSegments(projectId, currentSegments); + // 所有视频生成任务已成功提交到后端,立即扣费 + // allowNegative=true:Vidu 任务已提交,必须保证扣费成功,避免平台成本未收回 + progress.update('正在结算积分...'); + await pointsApi.consumePoints({ + points: actualVideoPoints, + sourceType: 'video', + sourceId: `video_${useAuthStore.getState().user?.id || 'unknown'}_${Date.now()}`, + description: '视频生成', + allowNegative: true, + }); + await fetchBalance(); + // ========== Step 2: 轮询视频生成任务状态 ========== const currentSegmentsForPoll = useProjectStore.getState().segments; const segmentShotsWithTask = currentSegmentsForPoll.filter( @@ -212,8 +268,13 @@ export function useVideoGeneration({ // 检查是否有失败的 const failed = states.filter(({ status }) => status.status === 'failed'); if (failed.length > 0) { - const failedIds = failed.map(({ shot }) => shot.id).join(', '); - throw new Error(`视频生成失败 (分镜 ${failedIds})`); + const firstWithError = failed.find(({ status }) => status.error); + const errorMsg = firstWithError?.status.error || `视频生成失败 (分镜 ${failed.map(({ shot }) => shot.id).join(', ')})`; + const err = new Error(errorMsg); + if (firstWithError?.status.errorCode) { + (err as Error & { errorCode?: string }).errorCode = firstWithError.status.errorCode; + } + throw err; } break; } @@ -348,52 +409,6 @@ export function useVideoGeneration({ const concatResult = await concatVideoClips(projectId, clipPaths); const finalVideoPath = concatResult.outputPath; - // 拼接成功后扣费:视频生成(按完整配音音频时长,允许欠费) - // - // ⚠️ 风险说明:扣费在前端执行,依赖用户保持应用开启直到拼接完成。 - // 如果用户在 Vidu 任务提交后关闭应用,Vidu 任务仍会在云端跑完 - //(callback 更新后端 registry),但前端不会再执行扣费逻辑。 - // 当前接受此风险:桌面应用用户通常会等待操作完成,关闭概率较低。 - // 后续若需根治,应将扣费移到后端 vidu_callback 中(每个分镜独立扣费)。 - // - // 优先使用 store 中已保存的音频时长(与按钮预估完全一致),降级时实时读取 - const storeAudioDuration = useProjectStore.getState().dubbingAudioDuration; - let totalAudioDuration: number; - if (storeAudioDuration && storeAudioDuration > 0) { - totalAudioDuration = storeAudioDuration; - } else { - const audioUrl = await getLocalFileUrl(dubbingAudioPath); - totalAudioDuration = await new Promise((resolve, reject) => { - const audio = new Audio(audioUrl); - const timeoutId = setTimeout(() => { - reject(new Error('读取音频时长超时,请检查音频文件')); - }, 15000); - audio.onloadedmetadata = () => { - clearTimeout(timeoutId); - resolve(audio.duration); - }; - audio.onerror = () => { - clearTimeout(timeoutId); - reject(new Error('读取音频时长失败')); - }; - }); - } - const baseVideoPoints = Math.ceil(totalAudioDuration) * videoMultiplier; - // 系统素材额外收费:每个空镜使用的系统素材额外 2 积分 - const systemMaterialCount = shots.filter((s: ScriptShot) => { - if (s.type !== 'empty_shot') {return false;} - const matched = materialMatchMap[String(s.id)]; - return matched && (matched.url.startsWith('http://') || matched.url.startsWith('https://')); - }).length; - const actualVideoPoints = baseVideoPoints + systemMaterialCount * 2; - await pointsApi.consumePoints({ - points: actualVideoPoints, - sourceType: 'video', - sourceId: `video_${useAuthStore.getState().user?.id || 'unknown'}_${Date.now()}`, - description: '视频生成', - }); - await fetchBalance(); - // 清理中间产物:删除 lipSyncVideoPath 和 clipVideoPath 对应的文件 const segmentsToClean = useProjectStore.getState().segments; for (const shot of segmentsToClean) { @@ -445,7 +460,20 @@ export function useVideoGeneration({ } catch (error) { console.error('[VideoGeneration] 生成失败:', error); const msg = getFriendlyErrorMessage(error, '视频生成失败,请稍后重试'); - if (handleError(error, '视频生成', estimatedVideoPoints)) { + + // 清理已提交的 taskId 与中间文件路径,避免重试时拿到脏状态 + const currentSegments = useProjectStore.getState().segments; + const cleanedSegments = currentSegments.map((s: ScriptShot) => ({ + ...s, + lipSyncTaskId: undefined, + lipSyncState: undefined, + lipSyncVideoPath: undefined, + clipVideoPath: undefined, + })); + useProjectStore.setState({ segments: cleanedSegments }); + await localProjectApi.saveSegments(projectId, cleanedSegments); + + if (handleError(error, actualVideoPoints)) { progress.hide(); } else { progress.error(msg); @@ -453,7 +481,10 @@ export function useVideoGeneration({ } finally { setIsComposing(false); } - }; + } finally { + generateLockRef.current = false; + } + }); return { isComposing, handleGenerate }; } diff --git a/tauri-app/src/pages/VideoGeneration/index.tsx b/tauri-app/src/pages/VideoGeneration/index.tsx index c307a36..c73ca91 100644 --- a/tauri-app/src/pages/VideoGeneration/index.tsx +++ b/tauri-app/src/pages/VideoGeneration/index.tsx @@ -249,7 +249,6 @@ export default function VideoGeneration() { const { isComposing, handleGenerate } = useVideoGeneration({ selectedAvatarMaterial, materialMatchMap, - estimatedVideoPoints, videoMultiplier, checkBalance, handleError, diff --git a/tauri-app/src/store/authStore.ts b/tauri-app/src/store/authStore.ts index 4aa4d4e..b39539c 100644 --- a/tauri-app/src/store/authStore.ts +++ b/tauri-app/src/store/authStore.ts @@ -41,7 +41,7 @@ interface AuthActions { logout: () => Promise; checkAuth: () => boolean; loadFromStorage: () => Promise; - closeKickModal: () => void; + closeKickModal: () => Promise; } @@ -64,6 +64,7 @@ let isLoggingIn = false; // SSE 连接(模块级,不放入 Zustand state,因为 EventSource 不可序列化) let _sseConnection: EventSource | null = null; +let _sseReconnectTimer: ReturnType | null = null; function connectSSE(accessToken: string) { disconnectSSE(); @@ -93,9 +94,14 @@ function connectSSE(accessToken: string) { console.error('[SSE] 连接错误,3秒后尝试重连'); es.close(); _sseConnection = null; - setTimeout(() => { - const { accessToken: currentToken } = useAuthStore.getState(); - if (currentToken) {connectSSE(currentToken);} + if (_sseReconnectTimer) { + clearTimeout(_sseReconnectTimer); + _sseReconnectTimer = null; + } + _sseReconnectTimer = setTimeout(() => { + _sseReconnectTimer = null; + const { accessToken: currentToken, showKickModal } = useAuthStore.getState(); + if (currentToken && !showKickModal) {connectSSE(currentToken);} }, 3000); }; @@ -107,6 +113,10 @@ function disconnectSSE() { _sseConnection.close(); _sseConnection = null; } + if (_sseReconnectTimer) { + clearTimeout(_sseReconnectTimer); + _sseReconnectTimer = null; + } } /** @@ -145,7 +155,7 @@ const generateDeviceId = () => { if (stored) { return stored; } - const newId = `web_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + const newId = `web_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`; localStorage.setItem('device_id', newId); return newId; }; @@ -247,7 +257,9 @@ export const useAuthStore = create((set, get) => ({ // 手机号验证码登录 login: async (phone: string, code: string) => { - if (isLoggingIn) {return;} + if (isLoggingIn) { + throw new Error('登录请求进行中,请勿重复提交'); + } isLoggingIn = true; try { @@ -276,7 +288,6 @@ export const useAuthStore = create((set, get) => ({ connectSSE(data.accessToken); } catch (error) { console.error('[authStore] 登录失败:', error); - isLoggingIn = false; throw error; } finally { isLoggingIn = false; @@ -285,7 +296,9 @@ export const useAuthStore = create((set, get) => ({ // 手机号密码登录 loginWithPassword: async (phone: string, password: string) => { - if (isLoggingIn) {return;} + if (isLoggingIn) { + throw new Error('登录请求进行中,请勿重复提交'); + } isLoggingIn = true; try { @@ -314,15 +327,14 @@ export const useAuthStore = create((set, get) => ({ connectSSE(data.accessToken); } catch (error) { console.error('[authStore] 密码登录失败:', error); - isLoggingIn = false; throw error; } finally { isLoggingIn = false; } }, - closeKickModal: () => { - clearAuthState(); + closeKickModal: async () => { + await clearAuthState(); set({ ...initialState, isLoading: false, showKickModal: false, kickMessage: '' }); // 清除其他 Store 的内存状态,防止被踢后重新登录时数据残留 try { diff --git a/tauri-app/src/store/projectStore.ts b/tauri-app/src/store/projectStore.ts index 8f66483..da53a70 100644 --- a/tauri-app/src/store/projectStore.ts +++ b/tauri-app/src/store/projectStore.ts @@ -23,10 +23,10 @@ interface ProjectActions { setCurrentStep: (_step: number) => void; setAvatarMaterial: (_path?: string, _name?: string, _duration?: number) => void; setSelectedVoiceId: (_voiceId: string) => void; - setFinalVideoPath: (_path: string | undefined) => void; - setCoverPath: (_path: string | undefined) => void; - setCoverConfig: (_config: ProjectState['coverConfig']) => void; - setExportedAt: (_timestamp: number | undefined) => void; + setFinalVideoPath: (_path: string | undefined) => Promise; + setCoverPath: (_path: string | undefined) => Promise; + setCoverConfig: (_config: ProjectState['coverConfig']) => Promise; + setExportedAt: (_timestamp: number | undefined) => Promise; setDubbingAudioDuration: (_duration: number | undefined) => void; setVoiceSpeed: (_speed: number) => void; setVoiceVolume: (_volume: number) => void; @@ -58,6 +58,8 @@ const initialState: Omit< title: '', status: 'draft', segments: [], + // localStorage 仅作为持久化层,Zustand state 为 currentProjectId 唯一真相源 + currentProjectId: getCurrentProjectId(), currentStep: 1, createdAt: 0, updatedAt: 0, @@ -81,35 +83,55 @@ let metaSavePromise: Promise = Promise.resolve(); * 3. 通过 Promise 链串行化,避免并发写导致数据丢失 */ export async function saveMetaToLocalFile(overrides: MetaOverrides = {}) { - const projectId = getCurrentProjectId(); + // currentProjectId 统一以 Zustand state 为唯一真相源 + const projectId = useProjectStore.getState().currentProjectId; if (!projectId) { - console.error('[ProjectStore] Cannot save meta: no project ID'); - return; + throw new Error('[ProjectStore] Cannot save meta: no project ID'); } - const task = async () => { - try { - const rawExisting = await localProjectApi.loadMeta(projectId); - const existing = rawExisting ? migrateMeta(rawExisting) : null; + const run = async () => { + const rawExisting = await localProjectApi.loadMeta(projectId); + const existing = rawExisting ? migrateMeta(rawExisting) : null; - // 核心:buildProjectMeta 自动合并所有字段,无需逐个判断 - const meta = buildProjectMeta(projectId, existing, overrides); + // 核心:buildProjectMeta 自动合并所有字段,无需逐个判断 + const meta = buildProjectMeta(projectId, existing, overrides); - await localProjectApi.saveMeta(projectId, meta); - } catch (err) { - console.error('[ProjectStore] Save meta failed:', err); - } + await localProjectApi.saveMeta(projectId, meta); }; - metaSavePromise = metaSavePromise.then(task).catch((err) => { - console.error('[ProjectStore] Save meta failed:', err); - throw err; - }); + // 前一个任务无论成功失败,都继续执行当前任务;当前任务失败会把错误抛给当前调用方 + metaSavePromise = metaSavePromise.then(run, run); await metaSavePromise; } -// 当前项目 ID(内存中) -let currentProjectId: string = getCurrentProjectId(); +/** + * 队列保存元数据,失败时只记录日志,不向上抛错。 + * 用于不关注保存结果、仅做状态同步的场景(例如切换音色、调整音量)。 + */ +function saveMetaSafely(overrides: MetaOverrides = {}) { + return saveMetaToLocalFile(overrides).catch((err) => { + console.error('[ProjectStore] 保存项目元数据失败:', err); + }); +} + +/** + * 归一化从磁盘读出的 segments,确保必填字段存在,避免强制类型转换导致运行时崩溃 + */ +function normalizeSegments(raw: unknown): ScriptShot[] { + if (!Array.isArray(raw)) { + return []; + } + return raw.map((item) => { + const s = (item ?? {}) as Partial; + return { + ...s, + id: s.id ?? 0, + type: s.type === 'empty_shot' ? 'empty_shot' : 'segment', + voiceover: s.voiceover ?? '', + duration: s.duration ?? '5s', + } as ScriptShot; + }); +} export const useProjectStore = create()( immer( @@ -121,11 +143,6 @@ export const useProjectStore = create()( return get()._hasHydrated; }, - // 获取当前项目 ID - get currentProjectId() { - return currentProjectId; - }, - setIsLoading: (loading: boolean) => set(state => { state._isLoading = loading; @@ -178,7 +195,7 @@ export const useProjectStore = create()( state.avatarMaterialDuration = duration; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ avatarMaterialPath: path, avatarMaterialName: name, avatarMaterialDuration: duration }); + saveMetaSafely({ avatarMaterialPath: path, avatarMaterialName: name, avatarMaterialDuration: duration }); }, setSelectedVoiceId: voiceId => { set(state => { @@ -186,40 +203,41 @@ export const useProjectStore = create()( state.updatedAt = Date.now(); }); }, + // 关键字段:保存失败需要让调用方感知,返回 Promise 供页面 await setFinalVideoPath: path => { set(state => { state.finalVideoPath = path; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ finalVideoPath: path }); + return saveMetaToLocalFile({ finalVideoPath: path }); }, setCoverPath: path => { set(state => { state.coverPath = path; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ coverPath: path }); + return saveMetaToLocalFile({ coverPath: path }); }, setCoverConfig: config => { set(state => { state.coverConfig = config; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ coverConfig: config }); + return saveMetaToLocalFile({ coverConfig: config }); }, setExportedAt: timestamp => { set(state => { state.exportedAt = timestamp; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ exportedAt: timestamp }); + return saveMetaToLocalFile({ exportedAt: timestamp }); }, setDubbingAudioDuration: duration => { set(state => { state.dubbingAudioDuration = duration; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ dubbingAudioDuration: duration }); + saveMetaSafely({ dubbingAudioDuration: duration }); }, setVoiceSpeed: speed => set(state => { @@ -238,28 +256,28 @@ export const useProjectStore = create()( state.bgmMusicPath = path; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ bgmMusicId: id, bgmMusicTitle: title, bgmMusicPath: path }); + saveMetaSafely({ bgmMusicId: id, bgmMusicTitle: title, bgmMusicPath: path }); }, setBgmVolume: volume => { set(state => { state.bgmVolume = volume; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ bgmVolume: volume }); + saveMetaSafely({ bgmVolume: volume }); }, setCategoryCode: code => { set(state => { state.categoryCode = code; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ categoryCode: code }); + saveMetaSafely({ categoryCode: code }); }, setFilename: filename => { set(state => { state.filename = filename; state.updatedAt = Date.now(); }); - saveMetaToLocalFile({ filename }); + saveMetaSafely({ filename }); }, markStepsDirty: (fromStep: number) => { @@ -277,7 +295,7 @@ export const useProjectStore = create()( for (let i = fromStep + 1; i <= 6; i++) { newFlags[i] = true; } - saveMetaToLocalFile({ stepDirtyFlags: { ...flags, ...newFlags } }); + saveMetaSafely({ stepDirtyFlags: { ...flags, ...newFlags } }); }, clearStepDirty: (stepId: number) => { @@ -288,15 +306,15 @@ export const useProjectStore = create()( state.updatedAt = Date.now(); }); const flags = get().stepDirtyFlags || {}; - saveMetaToLocalFile({ stepDirtyFlags: { ...flags, [stepId]: false } }); + saveMetaSafely({ stepDirtyFlags: { ...flags, [stepId]: false } }); }, reset: () => { - currentProjectId = ''; setCurrentProjectId(''); set({ ...initialState, ...BLANK_META_OVERRIDES, + currentProjectId: '', segments: [], _hasHydrated: true, }); @@ -321,6 +339,13 @@ export const useProjectStore = create()( ) ); +// 订阅 currentProjectId 变化,单向同步到 localStorage(持久化层) +useProjectStore.subscribe((state, prevState) => { + if (state.currentProjectId !== prevState.currentProjectId) { + setCurrentProjectId(state.currentProjectId); + } +}); + // 注:移除自动保存,改为在"进入第二步"时手动创建项目 // 符合文档逻辑:第一步完成进入第二步时创建项目文件 @@ -330,9 +355,8 @@ export const useProjectStore = create()( */ export async function initProjectStore(projectId?: string): Promise { const id = projectId || getCurrentProjectId(); - currentProjectId = id; setCurrentProjectId(id); - + useProjectStore.setState({ currentProjectId: id }); const { meta: rawMeta, segments } = await localProjectApi.loadProject(id); @@ -341,14 +365,16 @@ export async function initProjectStore(projectId?: string): Promise { // 先清空旧数据,再加载新项目数据,防止字段残留 useProjectStore.setState({ + ...initialState, ...BLANK_META_OVERRIDES, - segments: segments as ScriptShot[], + segments: normalizeSegments(segments), ...(meta || {}), _hasHydrated: true, }); } else { // 新项目 useProjectStore.setState({ + ...initialState, ...BLANK_META_OVERRIDES, segments: [], _hasHydrated: true, @@ -363,13 +389,13 @@ export async function initProjectStore(projectId?: string): Promise { */ export async function createNewProject(topic?: string, segments?: ScriptShot[]): Promise { const newId = generateProjectId(); - currentProjectId = newId; setCurrentProjectId(newId); // 彻底重置 Store,防止旧项目数据残留 useProjectStore.setState({ ...initialState, ...BLANK_META_OVERRIDES, + currentProjectId: newId, segments: segments || [], _hasHydrated: true, }); @@ -385,9 +411,9 @@ export async function createNewProject(topic?: string, segments?: ScriptShot[]): * 切换项目 */ export async function switchProject(projectId: string): Promise { - // 切换项目 ID - currentProjectId = projectId; + // 切换项目 ID,统一写入 Zustand state setCurrentProjectId(projectId); + useProjectStore.setState({ currentProjectId: projectId }); // 加载新项目 await initProjectStore(projectId); diff --git a/tauri-app/src/types/project.ts b/tauri-app/src/types/project.ts index 1b3b133..a709663 100644 --- a/tauri-app/src/types/project.ts +++ b/tauri-app/src/types/project.ts @@ -144,6 +144,7 @@ export interface ProjectMeta { export interface ProjectState extends ProjectMeta { segments: ScriptShot[]; + currentProjectId: string; _isLoading: boolean; _hasHydrated: boolean; // 以下字段在 ProjectMeta 中为可选,但在 Store 中始终有默认值,故覆盖为必需 diff --git a/tauri-app/src/utils/env.ts b/tauri-app/src/utils/env.ts index dbf6d58..3fb8c23 100644 --- a/tauri-app/src/utils/env.ts +++ b/tauri-app/src/utils/env.ts @@ -1,18 +1,9 @@ /** - * 环境检测工具 - * - * 统一的 Tauri 环境判断,避免各模块各自实现导致不一致。 + * 环境判断工具 + * ============ */ -interface TauriWindow extends Window { - __TAURI_INTERNALS__?: unknown; -} - +/** 当前是否运行在 Tauri 桌面应用环境中 */ export function isTauri(): boolean { - return ( - typeof window !== 'undefined' && - !!(window as TauriWindow).__TAURI_INTERNALS__ - ); + return typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window; } - - diff --git a/tauri-app/src/utils/errorMessage.ts b/tauri-app/src/utils/errorMessage.ts index 318b520..21baa99 100644 --- a/tauri-app/src/utils/errorMessage.ts +++ b/tauri-app/src/utils/errorMessage.ts @@ -2,47 +2,105 @@ * 错误信息友好化转换 * =================== * - * 将后端/底层技术错误翻译成终端用户能理解的提示文案。 + * 优先按后端返回的 error_code 识别错误类型,回退到原始错误文本兜底匹配。 */ +interface ErrorWithCode extends Error { + errorCode?: string; +} + +function getErrorCode(error: unknown): string | undefined { + return (error as ErrorWithCode).errorCode; +} + +function getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +/** + * 判断是否为积分不足错误 + */ +export function isInsufficientPointsError(error: unknown): boolean { + const errorCode = getErrorCode(error); + if (errorCode === 'insufficient_points') { + return true; + } + // 兜底:兼容旧后端或第三方错误 + const raw = getErrorMessage(error); + return raw.includes('积分不足') || raw.includes('402'); +} + +/** + * 判断是否为内容安全/审核不通过错误 + */ +export function isContentViolationError(error: unknown): boolean { + return getErrorCode(error) === 'content_violation'; +} + +/** + * 将错误转换为用户友好的提示文案 + */ export function getFriendlyErrorMessage(error: unknown, defaultMsg = '操作失败'): string { - const raw = error instanceof Error ? error.message : String(error); + const errorCode = getErrorCode(error); - // 提示词缺失 - if (raw.includes('未找到提示词') || raw.includes('prompt')) { - return '当前选择的创作类型暂不可用,请尝试其他类型或联系客服'; + // 1. 应用级结构化错误码(优先) + switch (errorCode) { + case 'content_violation': + return '人物分镜台词未通过安全审核,请修改后重试'; + case 'insufficient_points': + return '积分不足,请先充值后再尝试'; + case 'prompt_not_found': + return '当前选择的创作类型暂不可用,请尝试其他类型或联系客服'; + case 'empty_result': + return '生成内容为空,请调整创作主题后重试'; + case 'parse_error': + return '数据解析异常,请稍后重试或联系客服'; + case 'timeout': + return '服务响应超时,请稍后重试'; + case 'rate_limit': + return '当前请求过于频繁,请稍后再试'; + case 'auth_failed': + return '第三方服务认证失败,请稍后重试或联系客服'; + case 'quota_exhausted': + return '第三方服务额度已用完,请稍后重试或联系客服'; + case 'server_error': + return '第三方服务繁忙,请稍后重试'; + case 'bad_request': + return '请求参数错误,请检查后重试'; + case 'not_found': + return '请求的资源不存在,请检查后重试'; } - // 积分不足(通常由 usePointsCheck 拦截,兜底兼容) - if (raw.includes('积分不足') || raw.includes('402')) { - return '积分不足,请先充值后再尝试'; - } + // 2. 兜底:按原始错误文本关键词映射(兼容旧后端/网络层错误) + const raw = getErrorMessage(error).toLowerCase(); - // 网络/连接异常 if ( raw.includes('timeout') || raw.includes('超时') || - raw.includes('ETIMEDOUT') || - raw.includes('ECONNREFUSED') + raw.includes('etimedout') ) { return '服务响应超时,请稍后重试'; } + if ( raw.includes('network') || raw.includes('fetch') || - raw.includes('Failed to fetch') || - raw.includes('ECONNRESET') || - raw.includes('ENOTFOUND') + raw.includes('failed to fetch') || + raw.includes('econnrefused') || + raw.includes('econnreset') || + raw.includes('enotfound') ) { return '网络连接异常,请检查网络后重试'; } - // 生成结果为空 + if (raw.includes('未找到提示词') || raw.includes('prompt')) { + return '当前选择的创作类型暂不可用,请尝试其他类型或联系客服'; + } + if (raw.includes('任务结果为空') || raw.includes('生成分镜为空')) { return '生成内容为空,请调整创作主题后重试'; } - // 数据解析异常 if (raw.includes('数据解析失败') || raw.includes('数据适配失败')) { return '数据解析异常,请稍后重试或联系客服'; } diff --git a/tauri-app/src/utils/pendingOperations.ts b/tauri-app/src/utils/pendingOperations.ts new file mode 100644 index 0000000..6050301 --- /dev/null +++ b/tauri-app/src/utils/pendingOperations.ts @@ -0,0 +1,38 @@ +/** + * 全局飞行中操作计数器 + * ====================== + * + * 用于在窗口关闭时判断是否有未完成的第三方/本地任务,防止用户误操作导致 + * 已提交的任务或已扣除的积分无法回退。 + */ + +let pendingCount = 0; + +/** 是否有未完成的操作 */ +export function hasPendingOperations(): boolean { + return pendingCount > 0; +} + +/** 手动增加计数(慎用,建议优先使用 withPendingOperation) */ +export function addPendingOperation(): void { + pendingCount++; +} + +/** 手动减少计数 */ +export function removePendingOperation(): void { + pendingCount = Math.max(0, pendingCount - 1); +} + +/** + * 将 Promise 包装为“飞行中操作” + * + * 操作开始时计数 +1,结束后(成功/失败)计数 -1。 + */ +export async function withPendingOperation(fn: () => Promise): Promise { + addPendingOperation(); + try { + return await fn(); + } finally { + removePendingOperation(); + } +}