import re from typing import Any def msg_is_price_inquiry(msg: str) -> bool: if not msg: return False patterns = ("多少钱", "多少一张", "一张多少钱", "画图多少", "报价", "给个价", "几块", "多少钱") return any(p in msg for p in patterns) def detect_order_status(msg: str) -> str: if not msg: return "" s = msg if "买家已付款" in s or "已付款" in s: return "paid" if "[系统订单信息]" in s: if "等待买家付款" in s or "未付款" in s: return "waiting" return "order" return "" def msg_requests_external_contact(msg: str) -> bool: if not msg: return False lower = msg.lower() kws = ("加qq", "qq号", "vx", "微信", "加v", "联系方式", "私聊", "加一下", "加个", "手机号", "电话", "加群", "q q", "v 信") return any(k in lower for k in kws) def extract_size_pairs_m(msg: str) -> list[tuple[float, float]]: """提取消息中的米制尺寸对,如 15*6.4米 / 15米*6.4 / 15x6.4m。""" if not msg: return [] s = (msg or "").lower().replace("×", "*").replace("x", "*") pairs = [] patterns = [ r"(\d+(?:\.\d+)?)\s*\*\s*(\d+(?:\.\d+)?)\s*(?:米|m)\b", r"(\d+(?:\.\d+)?)\s*(?:米|m)\s*\*\s*(\d+(?:\.\d+)?)\b", ] for p in patterns: for m in re.findall(p, s): try: a = float(m[0]) b = float(m[1]) if a > 0 and b > 0: pairs.append((a, b)) except Exception: continue return pairs def oversize_reply_if_needed(msg: str) -> str: """ 检测超大尺寸需求并返回拒绝话术;未命中返回空字符串。 规则:最长边 > 阈值 或 面积 > 阈值。 """ try: from config.config import MAX_SERVICE_SIZE_LONGEST_METERS, MAX_SERVICE_SIZE_AREA_SQM longest_limit = float(MAX_SERVICE_SIZE_LONGEST_METERS) area_limit = float(MAX_SERVICE_SIZE_AREA_SQM) except Exception: longest_limit = 10.0 area_limit = 20.0 pairs = extract_size_pairs_m(msg) for w, h in pairs: longest = max(w, h) area = w * h if longest > longest_limit or area > area_limit: return ( f"{w:g}米*{h:g}米这个尺寸太大了,我们这边做不了。" "如果要做可以拆成几段小尺寸,我再给你按段评估。" ) return "" def build_auto_quote_signature(state: Any) -> str: from core.websocket_auto_quote_flow import build_auto_quote_signature as _build return _build(state)