fix: switch parse_mode to HTML to prevent BadRequest on special characters in names

This commit is contained in:
Power BI Dev
2026-06-04 09:59:49 +07:00
parent b031e30b1a
commit 532b614363
2 changed files with 61 additions and 62 deletions
+34 -35
View File
@@ -1,3 +1,4 @@
import html
from pathlib import Path
from telegram import Update
from telegram.ext import ContextTypes
@@ -24,17 +25,18 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
existing = db.get_user(user.id)
if existing:
name = html.escape(existing['full_name'])
await update.message.reply_text(
f"👋 Selamat datang kembali, *{existing['full_name']}*!\n"
f"👋 Selamat datang kembali, <b>{name}</b>!\n"
f"🧠 Second Brain Anda aktif. Gunakan /help untuk panduan.",
parse_mode="Markdown"
parse_mode="HTML"
)
return
if user.id == ADMIN_TELEGRAM_ID:
await update.message.reply_text(
"👑 *Mode Admin Aktif*\n\nGunakan /help_admin untuk melihat semua perintah admin.",
parse_mode="Markdown"
"👑 <b>Mode Admin Aktif</b>\n\nGunakan /help_admin untuk melihat semua perintah admin.",
parse_mode="HTML"
)
return
@@ -42,8 +44,8 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"👋 Halo! Bot ini khusus untuk dosen dengan token registrasi.\n\n"
"Hubungi admin untuk mendapatkan token, lalu kirim:\n"
"`/start TOKEN_ANDA`",
parse_mode="Markdown"
"<code>/start TOKEN_ANDA</code>",
parse_mode="HTML"
)
return
@@ -56,11 +58,11 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
full_name = user.full_name or user.username or "Dosen"
db.register_user(user.id, full_name, user.username or "", token)
await update.message.reply_text(
f"*Registrasi berhasil!*\n\n"
f"👤 {full_name}\n"
f"<b>Registrasi berhasil!</b>\n\n"
f"👤 {html.escape(full_name)}\n"
f"🧠 Second Brain Anda telah aktif.\n\n"
f"Gunakan /help untuk panduan lengkap.",
parse_mode="Markdown"
parse_mode="HTML"
)
@@ -76,7 +78,10 @@ async def remember(update: Update, context: ContextTypes.DEFAULT_TYPE):
content = " ".join(context.args)
mem_id = db.save_memory_meta(user_data["id"], content, scope="private")
await rag.add_memory(user_data["id"], mem_id, content, scope="private")
await update.message.reply_text(f"✅ Tersimpan di Second Brain:\n_{content}_", parse_mode="Markdown")
await update.message.reply_text(
f"✅ Tersimpan di Second Brain:\n<i>{html.escape(content)}</i>",
parse_mode="HTML"
)
async def recall(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -86,18 +91,16 @@ async def recall(update: Update, context: ContextTypes.DEFAULT_TYPE):
return
if not context.args:
# Tampilkan 10 catatan terbaru
memories = db.get_recent_memories(user_data["id"])
if not memories:
await update.message.reply_text("Second Brain Anda masih kosong. Gunakan /remember untuk menyimpan catatan.")
return
lines = ["🧠 *Catatan Terbaru:*\n"]
lines = ["🧠 <b>Catatan Terbaru:</b>\n"]
for m in memories:
lines.append(f"{m['content'][:150]}\n _{m['created_at'][:16]}_")
await update.message.reply_text("\n".join(lines), parse_mode="Markdown")
lines.append(f"{html.escape(m['content'][:150])}\n <i>{m['created_at'][:16]}</i>")
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
return
# Pencarian semantik
query = " ".join(context.args)
await update.message.chat.send_action("typing")
results = await rag.search(user_data["id"], query)
@@ -106,13 +109,12 @@ async def recall(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Tidak ada hasil yang relevan ditemukan.")
return
lines = [f"🔍 Hasil pencarian '{query}':\n"]
lines = [f"🔍 Hasil pencarian '<i>{html.escape(query)}</i>':\n"]
for i, r in enumerate(results, 1):
scope_label = "🌐 Global" if r["scope"] == "global" else "🔒 Pribadi"
# cosine distance: 0 = identik, 2 = berlawanan → konversi ke persentase
relevance = round(max(0, (1 - r["distance"])) * 100, 1)
lines.append(f"{i}. [{scope_label}] {r['content'][:200]}\n {relevance}% relevan\n")
await update.message.reply_text("\n".join(lines), parse_mode="Markdown")
lines.append(f"{i}. [{scope_label}] {html.escape(r['content'][:200])}\n {relevance}% relevan\n")
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
async def ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -127,12 +129,10 @@ async def ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
question = " ".join(context.args)
await update.message.chat.send_action("typing")
# Guard: hanya izinkan topik akademik
if not await is_academic_topic(question, _client, DEEPSEEK_MODEL):
await update.message.reply_text(REJECT_MESSAGE)
return
# Cari konteks relevan dari Second Brain
relevant = await rag.search(user_data["id"], question, n_results=5)
context_text = ""
if relevant:
@@ -169,7 +169,6 @@ async def ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def upload_doc(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Upload dokumen ke Second Brain pribadi."""
user_data = db.get_user(update.effective_user.id)
if not user_data:
await update.message.reply_text("⛔ Belum terdaftar.")
@@ -178,8 +177,8 @@ async def upload_doc(update: Update, context: ContextTypes.DEFAULT_TYPE):
doc = update.message.document
if not doc:
await update.message.reply_text(
"📎 Kirim file PDF, DOCX, atau TXT dengan caption `/upload`",
parse_mode="Markdown"
"📎 Kirim file PDF, DOCX, atau TXT dengan caption <code>/upload</code>",
parse_mode="HTML"
)
return
@@ -210,7 +209,7 @@ async def upload_doc(update: Update, context: ContextTypes.DEFAULT_TYPE):
await rag.add_document_chunks(user_id=user_data["id"], doc_id=doc_id, chunks=chunks, scope="private")
await update.message.reply_text(
f"{doc.file_name} berhasil diproses!\n"
f"{html.escape(doc.file_name)} berhasil diproses!\n"
f"📄 {len(chunks)} bagian tersimpan di Second Brain Anda.\n"
f"Gunakan /ask untuk bertanya tentang isi dokumen ini."
)
@@ -236,16 +235,16 @@ async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
return
text = (
"🧠 *Second Brain Bot — Panduan*\n\n"
"*Catatan:*\n"
"/remember `teks` — Simpan catatan baru\n"
"🧠 <b>Second Brain Bot — Panduan</b>\n\n"
"<b>Catatan:</b>\n"
"/remember <code>teks</code> — Simpan catatan baru\n"
"/recall — Lihat 10 catatan terbaru\n"
"/recall `kata kunci` — Cari dengan AI (semantik)\n\n"
"*Dokumen:*\n"
"📎 Kirim file + caption `/upload` — Upload PDF/DOCX/TXT\n\n"
"*Tanya AI:*\n"
"/ask `pertanyaan` — Tanya AI dengan konteks Second Brain\n"
"/recall <code>kata kunci</code> — Cari dengan AI (semantik)\n\n"
"<b>Dokumen:</b>\n"
"📎 Kirim file + caption <code>/upload</code> — Upload PDF/DOCX/TXT\n\n"
"<b>Tanya AI:</b>\n"
"/ask <code>pertanyaan</code> — Tanya AI dengan konteks Second Brain\n"
"/clear — Hapus riwayat percakapan\n\n"
"_Bot ini khusus untuk topik akademik dan perkuliahan._"
"<i>Bot ini khusus untuk topik akademik dan perkuliahan.</i>"
)
await update.message.reply_text(text, parse_mode="Markdown")
await update.message.reply_text(text, parse_mode="HTML")