AI Update: 📎 چرا این پاسخ اینجوری اوخد؟ چطوری اصلاحش کنیم؟

This commit is contained in:
Antigravity Bot
2026-08-31 10:52:40 +03:30
parent 56be74ccc9
commit d736659b2a
4 changed files with 340 additions and 9 deletions
+1 -1
View File
@@ -1801,7 +1801,7 @@ class AGYEngine:
text_out = rec["text"]
elif rec.get("tools"):
is_fa = (session.language or "").lower() in ("fa", "farsi", "persian", "🇮🇷 persian / farsi (فارسی)")
tool_bullets = "\n".join(f"<code>{t}</code>" for t in rec["tools"][-10:])
tool_bullets = "\n".join(f"`{t}`" for t in rec["tools"][-10:])
if is_fa:
text_out = f"✅ **دستورات و ابزارهای زیر با موفقیت اجرا شدند:**\n\n{tool_bullets}"
else:
+331
View File
@@ -5040,6 +5040,336 @@ async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data == "btn_ssh_menu":
text, markup = await build_ssh_menu(chat_id)
try:
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True)
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data.startswith("ssh_set:"):
field_name = data.split(":")[1]
if not curr_proj:
await query.answer("⚠️ پروژه‌ای یافت نشد." if is_fa else "⚠️ No project found.", show_alert=True)
return
USER_INPUT_STATES[chat_id] = {
"type": "ssh_set",
"field": field_name,
"project": curr_proj.name,
}
field_prompts = {
"host": (
"🌐 <b>لطفاً آدرس هاست یا IP سرور SSH را ارسال کنید:</b>\n\n"
"<i>مثال:</i> <code>server.mysite.com</code> یا <code>185.120.30.40:22</code>"
) if is_fa else (
"🌐 <b>Please enter the SSH Host/IP address:</b>\n\n"
"<i>Example:</i> <code>server.mysite.com</code> or <code>185.120.30.40:22</code>"
),
"user": (
"👤 <b>لطفاً نام کاربری اتصال SSH را ارسال کنید:</b>\n\n"
"<i>مثال:</i> <code>root</code> یا <code>ubuntu</code> یا <code>deployer</code>"
) if is_fa else (
"👤 <b>Please enter the SSH Username:</b>\n\n"
"<i>Example:</i> <code>root</code> or <code>ubuntu</code>"
),
"pass": (
"🔑 <b>لطفاً رمز عبور (Password) اتصال SSH را ارسال کنید:</b>\n\n"
"<i>(پیام ارسالی بلافاصله پس از ثبت جهت امنیت حذف خواهد شد)</i>"
) if is_fa else (
"🔑 <b>Please enter the SSH Password:</b>\n\n"
"<i>(Message will be deleted automatically for security)</i>"
),
"key": (
"🗝️ <b>لطفاً محتوای کلید خصوصی SSH Key (مانند OpenSSH/RSA/Ed25519) یا مسیر فایل آن را ارسال کنید:</b>\n\n"
"<i>مثال:</i> <code>-----BEGIN OPENSSH PRIVATE KEY----- ...</code>\n"
"<i>(پیام ارسالی بلافاصله جهت امنیت حذف خواهد شد)</i>"
) if is_fa else (
"🗝️ <b>Please send your SSH Private Key content or file path:</b>\n\n"
"<i>(Message will be deleted automatically for security)</i>"
),
"path": (
"📂 <b>لطفاً مسیر پوشه ریموت مقصد روی سرور را ارسال کنید:</b>\n\n"
"<i>مثال:</i> <code>/var/www/myproject</code> یا <code>/home/ubuntu/app</code>"
) if is_fa else (
"📂 <b>Please enter the remote directory path on the server:</b>\n\n"
"<i>Example:</i> <code>/var/www/myproject</code>"
),
}
prompt_text = field_prompts.get(field_name, "لطفاً مقدار جدید را ارسال کنید:")
cancel_kb = InlineKeyboardMarkup([[InlineKeyboardButton("❌ انصراف و بازگشت" if is_fa else "❌ Cancel", callback_data="btn_ssh_menu")]])
await query.edit_message_text(prompt_text, parse_mode=constants.ParseMode.HTML, reply_markup=cancel_kb)
elif data == "btn_ssh_exec_prompt":
if not curr_proj:
await query.answer("⚠️ پروژه‌ای یافت نشد." if is_fa else "⚠️ No project found.", show_alert=True)
return
if not curr_proj.ssh_host:
await query.answer("⚠️ ابتدا باید مشخصات هاست و سرور SSH را تنظیم نمایید.", show_alert=True)
return
USER_INPUT_STATES[chat_id] = {
"type": "ssh_exec",
"project": curr_proj.name,
}
msg = (
"💻 <b>اجرای فرمان در سرور ریموت SSH:</b>\n\n"
f"• 🌐 <b>سرور:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>مسیر:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n\n"
"لطفاً دستور مورد نظر خود را در یک پیام ارسال کنید:\n"
"<i>مثال:</i> <code>php -v</code> یا <code>git status</code> یا <code>systemctl status nginx</code>"
) if is_fa else (
"💻 <b>Run Remote SSH Command:</b>\n\n"
f"• 🌐 <b>Server:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>Path:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n\n"
"Please send the shell command to execute:"
)
cancel_kb = InlineKeyboardMarkup([[InlineKeyboardButton("❌ انصراف و بازگشت" if is_fa else "❌ Cancel", callback_data="btn_ssh_menu")]])
await query.edit_message_text(msg, parse_mode=constants.ParseMode.HTML, reply_markup=cancel_kb)
elif data == "ssh_clear_conf":
confirm_text = (
"🗑️ <b>آیا از پاک‌سازی کامل اطلاعات سرور SSH این پروژه اطمینان دارید؟</b>\n\n"
"تمام مشخصات هاست، نام کاربری، رمز عبور و کلید SSH حذف خواهند شد."
) if is_fa else (
"🗑️ <b>Are you sure you want to clear SSH settings for this project?</b>"
)
keyboard = [
[
InlineKeyboardButton("💥 بله، پاک شود" if is_fa else "💥 Yes, Clear", callback_data="ssh_clear_do"),
InlineKeyboardButton("❌ انصراف" if is_fa else "❌ Cancel", callback_data="btn_ssh_menu"),
]
]
await query.edit_message_text(confirm_text, parse_mode=constants.ParseMode.HTML, reply_markup=InlineKeyboardMarkup(keyboard))
elif data == "ssh_clear_do":
if curr_proj:
curr_proj.ssh_host = None
curr_proj.ssh_port = 22
curr_proj.ssh_user = None
curr_proj.ssh_password = None
curr_proj.ssh_key = None
curr_proj.ssh_path = "/"
session_manager.save()
remote_audit.log_operation(
user_id=chat_id,
project_name=curr_proj.name,
service_type="ssh",
action_type="update_config",
requester="user_button",
status="success",
details="Cleared SSH config",
result_summary="SSH configuration cleared",
)
await query.answer("🗑️ اطلاعات SSH با موفقیت پاک شد." if is_fa else "🗑️ SSH settings cleared.")
text, markup = await build_ssh_menu(chat_id)
try:
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True)
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data == "btn_ssh_test":
await query.answer("🔍 در حال بررسی اتصال SSH..." if is_fa else "🔍 Testing SSH connection...")
if curr_proj and curr_proj.ssh_host:
test_ok, test_msg = await ssh_manager.test_connection(
host=curr_proj.ssh_host,
port=curr_proj.ssh_port,
user=curr_proj.ssh_user or "",
password=curr_proj.ssh_password,
key=curr_proj.ssh_key,
path=curr_proj.ssh_path or "/",
user_id=chat_id,
project_name=curr_proj.name,
requester="user_button",
)
icon = "" if test_ok else ""
res_card = (
f"{icon} <b>نتیجه تست اتصال SSH:</b>\n\n"
f"• 🌐 <b>هاست:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 👤 <b>نام کاربری:</b> <code>{escape_html(curr_proj.ssh_user or '(بدون نام کاربری)')}</code>\n"
f"• 📂 <b>مسیر:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n\n"
f"📋 <b>گزارش ارتباط:</b>\n{test_msg}"
) if is_fa else (
f"{icon} <b>SSH Connection Test Result:</b>\n\n"
f"• 🌐 <b>Host:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 👤 <b>User:</b> <code>{escape_html(curr_proj.ssh_user or '(none)')}</code>\n"
f"• 📂 <b>Path:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n\n"
f"📋 <b>Status:</b>\n{test_msg}"
)
try:
await query.message.reply_html(res_card, disable_web_page_preview=True)
except Exception:
pass
else:
try:
await query.answer("⚠️ اطلاعات SSH هنوز برای این پروژه تنظیم نشده است.", show_alert=True)
except Exception:
pass
text, markup = await build_ssh_menu(chat_id)
try:
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True)
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data == "btn_ssh_push":
await query.answer("🚀 در حال ارسال شاخه پروداکشن به سرور SSH..." if is_fa else "🚀 Pushing production to SSH...")
if curr_proj and curr_proj.ssh_host:
status_msg = await query.message.reply_html("🚀 <i>در حال ارسال کدهای شاخه production به سرور SSH...</i>" if is_fa else "🚀 <i>Uploading production branch files via SFTP...</i>")
res = await ssh_manager.push_project(
workspace_path=curr_proj.workspace,
host=curr_proj.ssh_host,
port=curr_proj.ssh_port,
user=curr_proj.ssh_user or "",
password=curr_proj.ssh_password,
key=curr_proj.ssh_key,
remote_path=curr_proj.ssh_path or "/",
branch="production",
user_id=chat_id,
project_name=curr_proj.name,
requester="user_button",
)
if res.get("success"):
files_up = res.get("files_uploaded", 0)
files_skip = res.get("files_skipped", 0)
dur = round(res.get("duration", 0), 2)
b_trans = res.get("bytes_transferred", 0)
size_mb = f"{b_trans / (1024 * 1024):.2f} MB" if b_trans > 1024 * 1024 else f"{b_trans / 1024:.1f} KB"
report = (
f"✅ <b>پوش به سرور پروداکشن با موفقیت انجام شد!</b>\n\n"
f"• 📁 <b>پروژه:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 🌿 <b>شاخه مبدأ:</b> <code>production</code>\n"
f"• 🌐 <b>سرور مقصد:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>مسیر سرور:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n"
f"• 📦 <b>تعداد فایل‌های آپلود شده:</b> {files_up}\n"
f"• 🛡️ <b>فایل‌های محلی/دیتابیس فیلتر شده:</b> {files_skip}\n"
f"• 🔒 <b>داده‌های سرور پروداکشن:</b> کاملاً دست‌نخورده و ایمن حفظ شدند\n"
f"• 📊 <b>حجم کل منتقل شده:</b> {size_mb}\n"
f"• ⏱️ <b>مدت زمان انتقال:</b> {dur} ثانیه"
) if is_fa else (
f"✅ <b>SSH Push Completed Successfully!</b>\n\n"
f"• 📁 <b>Project:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 🌿 <b>Source Branch:</b> <code>production</code>\n"
f"• 🌐 <b>Target Server:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>Remote Path:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n"
f"• 📦 <b>Files Uploaded:</b> {files_up}\n"
f"• 🛡️ <b>Skipped Junk/Databases:</b> {files_skip}\n"
f"• 🔒 <b>Remote Production Data:</b> Safe & Untouched\n"
f"• 📊 <b>Transferred:</b> {size_mb}\n"
f"• ⏱️ <b>Duration:</b> {dur}s"
)
try:
await status_msg.edit_text(report, parse_mode=constants.ParseMode.HTML)
except Exception:
pass
else:
err = res.get("error", "Error")
err_report = (
f"❌ <b>خطا در پوش به سرور SSH:</b>\n\n"
f"• ⚠️ <b>پیام خطا:</b> {escape_html(str(err))}\n"
f"• 💡 <i>پیشنهاد: ابتدا دکمه تست اتصال را بررسی کنید یا دسترسی‌های دایرکتوری سرور را چک فرمایید.</i>"
) if is_fa else f"❌ <b>SSH Push Error:</b>\n{escape_html(str(err))}"
try:
await status_msg.edit_text(err_report, parse_mode=constants.ParseMode.HTML)
except Exception:
pass
else:
try:
await query.answer("⚠️ اطلاعات SSH تنظیم نشده است.", show_alert=True)
except Exception:
pass
text, markup = await build_ssh_menu(chat_id)
try:
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True)
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data == "btn_ssh_pull":
await query.answer("📥 در حال دریافت فایل‌ها از سرور SSH..." if is_fa else "📥 Pulling files from SSH server...")
if curr_proj and curr_proj.ssh_host:
status_msg = await query.message.reply_html("📥 <i>در حال دانلود فایل‌های پروژه از سرور SSH...</i>" if is_fa else "📥 <i>Downloading files via SFTP...</i>")
res = await ssh_manager.pull_project(
workspace_path=curr_proj.workspace,
host=curr_proj.ssh_host,
port=curr_proj.ssh_port,
user=curr_proj.ssh_user or "",
password=curr_proj.ssh_password,
key=curr_proj.ssh_key,
remote_path=curr_proj.ssh_path or "/",
branch="production",
user_id=chat_id,
project_name=curr_proj.name,
requester="user_button",
)
if res.get("success"):
files_down = res.get("files_downloaded", 0)
files_skip = res.get("files_skipped", 0)
dur = round(res.get("duration", 0), 2)
b_trans = res.get("bytes_transferred", 0)
size_mb = f"{b_trans / (1024 * 1024):.2f} MB" if b_trans > 1024 * 1024 else f"{b_trans / 1024:.1f} KB"
report = (
f"✅ <b>دریافت فایل‌ها (Pull) با موفقیت انجام شد!</b>\n\n"
f"• 📁 <b>پروژه:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 🌐 <b>سرور مبدأ:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>مسیر سرور:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n"
f"• 📦 <b>تعداد فایل‌های دریافت شده:</b> {files_down}\n"
f"• 🛡️ <b>فایل‌های نادیده گرفته‌شده (دیتابیس/لاگ):</b> {files_skip}\n"
f"• 📊 <b>حجم کل دانلود شده:</b> {size_mb}\n"
f"• ⏱️ <b>مدت زمان انتقال:</b> {dur} ثانیه"
) if is_fa else (
f"✅ <b>SSH Pull Completed Successfully!</b>\n\n"
f"• 📁 <b>Project:</b> <code>{escape_html(curr_proj.name)}</code>\n"
f"• 🌐 <b>Source Server:</b> <code>{escape_html(curr_proj.ssh_host)}:{curr_proj.ssh_port}</code>\n"
f"• 📂 <b>Remote Path:</b> <code>{escape_html(curr_proj.ssh_path or '/')}</code>\n"
f"• 📦 <b>Files Downloaded:</b> {files_down}\n"
f"• 🛡️ <b>Skipped (Databases/Logs):</b> {files_skip}\n"
f"• 📊 <b>Transferred:</b> {size_mb}\n"
f"• ⏱️ <b>Duration:</b> {dur}s"
)
try:
await status_msg.edit_text(report, parse_mode=constants.ParseMode.HTML)
except Exception:
pass
else:
err = res.get("error", "Error")
err_report = (
f"❌ <b>خطا در دریافت از سرور SSH:</b>\n\n"
f"• ⚠️ <b>پیام خطا:</b> {escape_html(str(err))}\n"
) if is_fa else f"❌ <b>SSH Pull Error:</b>\n{escape_html(str(err))}"
try:
await status_msg.edit_text(err_report, parse_mode=constants.ParseMode.HTML)
except Exception:
pass
else:
try:
await query.answer("⚠️ اطلاعات SSH تنظیم نشده است.", show_alert=True)
except Exception:
pass
text, markup = await build_ssh_menu(chat_id)
try:
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup, disable_web_page_preview=True)
except Exception:
await query.message.reply_html(text, reply_markup=markup, disable_web_page_preview=True)
elif data == "btn_ssh_logs":
await query.answer("📜 در حال دریافت تاریخچه..." if is_fa else "📜 Loading logs...")
proj_name = curr_proj.name if curr_proj else "default"
logs = remote_audit.get_recent_logs(user_id=chat_id, project_name=proj_name, limit=12)
log_text = remote_audit.format_logs_for_tg(logs, project_name=proj_name, is_fa=is_fa)
back_kb = InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت به منوی SSH" if is_fa else "🔙 Back to SSH", callback_data="btn_ssh_menu")]])
try:
await query.edit_message_text(log_text, parse_mode=constants.ParseMode.HTML, reply_markup=back_kb)
except Exception:
await query.message.reply_html(log_text, reply_markup=back_kb)
elif data == "btn_git_sync":
await query.answer("🔄 در حال همگام‌سازی با Gitea..." if is_fa else "🔄 Syncing with Gitea...")
if curr_proj:
@@ -7663,6 +7993,7 @@ def main():
application.add_handler(CommandHandler(["git", "repo", "repository", "gitea"], git_command))
application.add_handler(CommandHandler(["publish", "gitpublish", "release"], publish_command))
application.add_handler(CommandHandler(["ftp", "ftpdeploy", "deploy"], ftp_command))
application.add_handler(CommandHandler(["ssh", "remotedev", "sshdev", "remote"], ssh_command))
application.add_handler(CommandHandler(["sync", "gitsync", "pull"], sync_command))
application.add_handler(CommandHandler(["commit", "gitcommit"], commit_command))
application.add_handler(CommandHandler(["undo", "revert", "gitundo", "gitrevert", "laghv"], undo_command))
File diff suppressed because one or more lines are too long