feat: interactive inline buttons, SMTP reply, AI reply suggestions
- Inline keyboard: view original / back to summary toggle per message - SMTP config per account for sending replies - Reply button: click, type message, auto-send via SMTP - AI Reply button: generates 3 suggestions via DeepSeek - Simple replies (OK, Got it) send immediately on tap - Substantive replies require confirm before send - Hides AI Reply button when AI determines reply unnecessary - Telegram long polling integrated into main loop for real-time interaction
This commit is contained in:
7 files changed
+410
-48
No files matched your search
+16
-3
@@ -1,14 +1,23 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass
|
||||
class SmtpConfig:
|
||||
server: str
|
||||
port: int
|
||||
use_ssl: bool = True
|
||||
use_starttls: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class EmailAccount:
|
||||
imap_server: str
|
||||
imap_port: int
|
||||
username: str
|
||||
password: str
|
||||
smtp: Optional[SmtpConfig] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -41,7 +50,11 @@ def load_config(path: str) -> Config:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
raw = yaml.safe_load(f)
|
||||
|
||||
accounts = [EmailAccount(**a) for a in raw["email_accounts"]]
|
||||
accounts = []
|
||||
for a in raw["email_accounts"]:
|
||||
if "smtp" in a and a["smtp"] is not None:
|
||||
a["smtp"] = SmtpConfig(**a["smtp"])
|
||||
accounts.append(EmailAccount(**a))
|
||||
ai = AIConfig(**raw["ai"])
|
||||
tg = TelegramConfig(**raw["telegram"])
|
||||
polling = PollingConfig(**raw["polling"])
|
||||
|
||||