87 lines
2.3 KiB
Python
87 lines
2.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from dataclasses import dataclass, field
|
||
|
|
from enum import StrEnum
|
||
|
|
|
||
|
|
|
||
|
|
class KeyboardScope(StrEnum):
|
||
|
|
OFF = "off"
|
||
|
|
DM = "dm"
|
||
|
|
GROUP = "group"
|
||
|
|
ALL = "all"
|
||
|
|
ALLOWLIST = "allowlist"
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class InlineButton:
|
||
|
|
text: str
|
||
|
|
url: str | None = None
|
||
|
|
callback_data: str | None = None
|
||
|
|
copy_text: str | None = None
|
||
|
|
style: str | None = None
|
||
|
|
icon_custom_emoji_id: str | None = None
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class InlineKeyboard:
|
||
|
|
rows: list[list[InlineButton]] = field(default_factory=list)
|
||
|
|
|
||
|
|
def to_telegram_markup(self) -> dict | None:
|
||
|
|
if not self.rows:
|
||
|
|
return None
|
||
|
|
return {
|
||
|
|
"inline_keyboard": [
|
||
|
|
[
|
||
|
|
_build_button_cell(btn)
|
||
|
|
for btn in row
|
||
|
|
]
|
||
|
|
for row in self.rows
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def _build_button_cell(btn: InlineButton) -> dict:
|
||
|
|
cell: dict = {"text": btn.text}
|
||
|
|
if btn.url:
|
||
|
|
cell["url"] = btn.url
|
||
|
|
elif btn.callback_data:
|
||
|
|
cell["callback_data"] = btn.callback_data
|
||
|
|
if btn.copy_text:
|
||
|
|
cell["copy_text"] = {"text": btn.copy_text}
|
||
|
|
if btn.style:
|
||
|
|
cell["style"] = btn.style
|
||
|
|
if btn.icon_custom_emoji_id:
|
||
|
|
cell["icon_custom_emoji_id"] = btn.icon_custom_emoji_id
|
||
|
|
return cell
|
||
|
|
|
||
|
|
|
||
|
|
def build_model_selector(models: list[str], selected: str | None = None, prefix: str = "model") -> InlineKeyboard:
|
||
|
|
if not models:
|
||
|
|
return InlineKeyboard()
|
||
|
|
|
||
|
|
rows: list[list[InlineButton]] = []
|
||
|
|
current_row: list[InlineButton] = []
|
||
|
|
|
||
|
|
for i, model in enumerate(models):
|
||
|
|
label = f"{'✅ ' if model == selected else ''}{model}"
|
||
|
|
btn = InlineButton(text=label, callback_data=f"{prefix}:{model}")
|
||
|
|
current_row.append(btn)
|
||
|
|
|
||
|
|
if len(current_row) >= 2 or i == len(models) - 1:
|
||
|
|
rows.append(current_row)
|
||
|
|
current_row = []
|
||
|
|
|
||
|
|
if current_row:
|
||
|
|
rows.append(current_row)
|
||
|
|
|
||
|
|
return InlineKeyboard(rows=rows)
|
||
|
|
|
||
|
|
|
||
|
|
def build_approval_keyboard(action_id: str) -> InlineKeyboard:
|
||
|
|
return InlineKeyboard(rows=[
|
||
|
|
[
|
||
|
|
InlineButton(text="✅ 批准", callback_data=f"approval:approve:{action_id}"),
|
||
|
|
InlineButton(text="❌ 拒绝", callback_data=f"approval:reject:{action_id}"),
|
||
|
|
]
|
||
|
|
])
|