feat: open bot access and guide invalid delivery queries

This commit is contained in:
ar51
2026-09-28 10:05:53 +08:00
parent 1c25c9e1d9
commit f35351d540
8 changed files with 101 additions and 47 deletions

View File

@@ -242,11 +242,7 @@ def parse_request(text: str) -> RequestInput:
def parse_trigger_request(text: str) -> RequestInput | None:
"""Return a query only when one complete model and one quantity are present.
Feishu group messages that do not satisfy the complete AM516 input contract
are unrelated traffic from the bridge's point of view and must stay silent.
"""
"""Return a query only when one complete model and one quantity are present."""
try:
return parse_request(text)
except InputError:
@@ -993,14 +989,6 @@ def message_text(data: lark.im.v1.P2ImMessageReceiveV1) -> str | None:
return text if isinstance(text, str) else None
def is_allowed_sender(data: lark.im.v1.P2ImMessageReceiveV1) -> bool:
allowed = {item.strip() for item in os.getenv("FEISHU_BOT_ALLOWED_OPEN_IDS", "").split(",") if item.strip()}
if not allowed:
return True
sender_id = data.event.sender.sender_id
return bool(sender_id and sender_id.open_id in allowed)
def post_paragraph(line: str) -> list[dict[str, Any]]:
element: dict[str, Any] = {"tag": "text", "text": line or " "}
if (
@@ -1102,10 +1090,45 @@ _seen_message_ids: set[str] = set()
_seen_message_lock = threading.Lock()
def input_guidance(data: lark.im.v1.P2ImMessageReceiveV1, text: str | None) -> str | None:
"""Help direct-message users and relevant group queries without calling the API."""
message = data.event.message
normalized = unicodedata.normalize("NFKC", text or "").lower()
if getattr(message, "chat_type", None) != "p2p" and not any(
word in normalized for word in ("erob", "am516", "交期", "候选型号")
):
return None
if text and is_candidate_continuation_request(text):
reason = "当前没有可继续的查询,请重新发送完整型号和数量。"
elif text:
try:
parse_request(text)
except InputError as exc:
reason = str(exc)
else:
return None
else:
reason = "请使用文字发送型号和数量,暂不支持从图片、文件或语音中识别。"
return (
f"AM516 交期查询使用说明\n\n{reason}\n\n"
"请一次发送一个完整 eRob 型号(含版本)和一个正整数数量。\n"
"提问示例:\neRob110H160I-FHM-18ET[V6] 10台\n\n"
"也可以说:请查询 eRob110H160I-FHM-18ET[V6],数量10台的交期。\n"
"请将示例替换为实际型号和数量;多个型号请分条发送。\n"
"收到结果后,可在同一聊天中发送“还有没有其他候选型号”。\n\n"
f"{DISCLAIMER}"
)
def handle_message(client: lark.Client, data: lark.im.v1.P2ImMessageReceiveV1) -> None:
text = message_text(data)
message_id = data.event.message.message_id
if not text or not message_id:
if not message_id:
return
if not text:
guidance = input_guidance(data, text)
if guidance:
reply(client, message_id, guidance)
return
key = conversation_key(data)
@@ -1118,6 +1141,10 @@ def handle_message(client: lark.Client, data: lark.im.v1.P2ImMessageReceiveV1) -
request = continuation_state.request
candidate_offset = continuation_state.next_offset
if request is None:
guidance = input_guidance(data, text)
if guidance:
reply(client, message_id, guidance)
return
logging.info(
"Feishu message ignored: no complete AM516 request or active candidate continuation; message_id=%s",
message_id,
@@ -1173,7 +1200,7 @@ def main() -> None:
message_id = data.event.message.message_id
sender_type = data.event.sender.sender_type
logging.info("Feishu event received: message_id=%s sender_type=%s", message_id, sender_type)
if data.event.sender.sender_type != "user" or not is_allowed_sender(data):
if data.event.sender.sender_type != "user":
return
if not message_id:
return