from __future__ import annotations import re QUICK_REPLIES_RE = re.compile(r"\[\[quick_replies:\s*(.+?)\]\]") CONFIRM_RE = re.compile(r"\[\[confirm:\s*(.+?)\|\s*(.+?)\|\s*(.+?)\]\]") BUTTONS_RE = re.compile(r"\[\[buttons:\s*(.+?)\]\]") LOCATION_RE = re.compile(r"\[\[location:\s*(.+?)\]\]") _MAX_DIRECTIVES = 5 def parse_line_directives(text: str) -> list[dict] | None: if not text or not text.strip(): return None result: list[dict] = [] qr_match = QUICK_REPLIES_RE.search(text) if qr_match and len(result) < _MAX_DIRECTIVES: labels = [lbl.strip() for lbl in qr_match.group(1).split(",") if lbl.strip()] main_text = QUICK_REPLIES_RE.sub("", text).strip() items = [ { "type": "action", "action": {"type": "message", "label": label[:20], "text": label}, } for label in labels[:13] ] if items: result.append( { "type": "text", "text": main_text[:5000], "quickReply": {"items": items}, } ) cf_match = CONFIRM_RE.search(text) if cf_match and len(result) < _MAX_DIRECTIVES: question = cf_match.group(1).strip() yes_label = cf_match.group(2).strip() no_label = cf_match.group(3).strip() main_text = CONFIRM_RE.sub("", text).strip() if main_text and question: result.append({"type": "text", "text": main_text[:5000]}) if question: result.append( { "type": "template", "altText": question[:400], "template": { "type": "confirm", "text": question[:240], "actions": [ {"type": "message", "label": yes_label[:20], "text": "yes"}, {"type": "message", "label": no_label[:20], "text": "no"}, ], }, } ) btn_match = BUTTONS_RE.search(text) if btn_match and len(result) < _MAX_DIRECTIVES: parts = [p.strip() for p in btn_match.group(1).split("|")] if len(parts) >= 1: title = parts[0] if len(parts) > 0 else "" description = parts[1] if len(parts) > 1 else "" btn_defs = parts[2] if len(parts) > 2 else "" actions = [] if btn_defs.strip(): for btn_def in btn_defs.split(",")[:4]: btn_def = btn_def.strip() if not btn_def: continue if ":" in btn_def: b_label, b_data = btn_def.split(":", 1) b_label, b_data = b_label.strip(), b_data.strip() if b_data.startswith("https://"): actions.append({"type": "uri", "label": b_label[:20], "uri": b_data}) else: actions.append({"type": "message", "label": b_label[:20], "text": b_data}) main_text = BUTTONS_RE.sub("", text).strip() if main_text: result.append({"type": "text", "text": main_text[:5000]}) if title and actions: result.append( { "type": "template", "altText": title[:400], "template": { "type": "buttons", "title": title[:40], "text": description[:160], "actions": actions, }, } ) loc_match = LOCATION_RE.search(text) if loc_match and len(result) < _MAX_DIRECTIVES: parts = [p.strip() for p in loc_match.group(1).split("|")] if len(parts) >= 4: title, address = parts[0], parts[1] try: lat, lon = float(parts[2]), float(parts[3]) except ValueError: lat, lon = 0.0, 0.0 main_text = LOCATION_RE.sub("", text).strip() if main_text: result.append({"type": "text", "text": main_text[:5000]}) result.append( { "type": "location", "title": title[:100], "address": address[:100], "latitude": lat, "longitude": lon, } ) return result[:_MAX_DIRECTIVES] if result else None