AI Update: امکان اضافه کردن حافظه را به دکمه های ربات اضافه کن
This commit is contained in:
+290
-10
@@ -614,15 +614,18 @@ def build_projects_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
|
||||
InlineKeyboardButton("🤝 اشتراکگذاری", callback_data="proj_share_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🧠 حافظه پروژه", callback_data="mem_tab:project:0"),
|
||||
InlineKeyboardButton("📂 مسیر کاری", callback_data="proj_ws_info"),
|
||||
InlineKeyboardButton("🗑️ حذف پروژه", callback_data="proj_del_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔄 ریاستارت گفتگو", callback_data="btn_restart"),
|
||||
InlineKeyboardButton("🗑️ حذف پروژه", callback_data="proj_del_menu"),
|
||||
InlineKeyboardButton("🧠 انتخاب مدل", callback_data="proj_model_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔄 ریاستارت گفتگو", callback_data="btn_restart"),
|
||||
InlineKeyboardButton("🏠 منوی اصلی", callback_data="btn_dashboard"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔙 بستن منو", callback_data="proj_close"),
|
||||
])
|
||||
else:
|
||||
@@ -635,15 +638,18 @@ def build_projects_menu(chat_id: int) -> tuple[str, InlineKeyboardMarkup]:
|
||||
InlineKeyboardButton("🤝 Share Project", callback_data="proj_share_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🧠 Project Memory", callback_data="mem_tab:project:0"),
|
||||
InlineKeyboardButton("📂 Workspace Info", callback_data="proj_ws_info"),
|
||||
InlineKeyboardButton("🗑️ Delete Project", callback_data="proj_del_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔄 Reset Chat", callback_data="btn_restart"),
|
||||
InlineKeyboardButton("🗑️ Delete Project", callback_data="proj_del_menu"),
|
||||
InlineKeyboardButton("🧠 Switch Model", callback_data="proj_model_menu"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔄 Reset Chat", callback_data="btn_restart"),
|
||||
InlineKeyboardButton("🏠 Main Dashboard", callback_data="btn_dashboard"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔙 Close", callback_data="proj_close"),
|
||||
])
|
||||
|
||||
@@ -1253,15 +1259,16 @@ def build_memory_menu(chat_id: int, view_type: str = "project", page: int = 0) -
|
||||
pag_row.append(InlineKeyboardButton("بعدی ➡️" if is_fa else "Next ➡️", callback_data=f"mem_tab:{view_type}:{page + 1}"))
|
||||
keyboard.append(pag_row)
|
||||
|
||||
# 4. Clear memory button
|
||||
action_row = []
|
||||
# 4. Action buttons (Add, Clear, Refresh)
|
||||
action_row = [
|
||||
InlineKeyboardButton("➕ افزودن خاطره" if is_fa else "➕ Add Memory", callback_data=f"mem_add_menu:{view_type}"),
|
||||
]
|
||||
if can_delete_current and total_cnt > 0:
|
||||
clear_label = "🧹 پاکسازی این بخش" if is_fa else "🧹 Clear this section"
|
||||
action_row.append(InlineKeyboardButton(clear_label, callback_data=f"mem_clear_conf:{view_type}"))
|
||||
|
||||
action_row.append(InlineKeyboardButton("🔄 تازهسازی" if is_fa else "🔄 Refresh", callback_data=f"mem_tab:{view_type}:{page}"))
|
||||
if action_row:
|
||||
keyboard.append(action_row)
|
||||
keyboard.append(action_row)
|
||||
|
||||
# 5. Main menu button
|
||||
keyboard.append([
|
||||
@@ -1272,6 +1279,229 @@ def build_memory_menu(chat_id: int, view_type: str = "project", page: int = 0) -
|
||||
return text, InlineKeyboardMarkup(keyboard)
|
||||
|
||||
|
||||
MEMORY_PRESETS = {
|
||||
"project": {
|
||||
"php_caddy": {
|
||||
"key": "php_caddy_stack",
|
||||
"category": "tech_stack",
|
||||
"content": "همیشه از PHP 8.x مدرن به عنوان زبان اصلی بکاند و سرور Caddy برای Reverse Proxy و مدیریت خودکار SSL دامنه msa.artacloud.ir استفاده شود.",
|
||||
"content_en": "Always use modern PHP 8.x as backend and Caddy reverse proxy for msa.artacloud.ir domains with automatic SSL.",
|
||||
},
|
||||
"qa_tests": {
|
||||
"key": "qa_and_verification",
|
||||
"category": "rule",
|
||||
"content": "قبل از اتمام کار، تمام کدها، مسیرها، سینتکس و سرویسها باید به طور کامل تست، عیبیابی و اعتبارسنجی شوند.",
|
||||
"content_en": "Always test, verify syntax, and perform QA audit before marking tasks complete.",
|
||||
},
|
||||
"clean_code": {
|
||||
"key": "clean_code_standards",
|
||||
"category": "rule",
|
||||
"content": "ساختار تمیز دایرکتوریها، تفکیک فایلها، کامنتهای معنادار و الگوهای خوانا رعایت شوند.",
|
||||
"content_en": "Follow clean code architecture, proper folder structure, and meaningful documentation.",
|
||||
},
|
||||
},
|
||||
"user": {
|
||||
"lang_fa": {
|
||||
"key": "preferred_language",
|
||||
"category": "preference",
|
||||
"content": "همیشه تمام مکالمات، توضیحات، و پیامها به زبان فارسی روان و دقیق ارائه شوند.",
|
||||
"content_en": "Always communicate and explain in fluent Persian.",
|
||||
},
|
||||
"concise_style": {
|
||||
"key": "response_style",
|
||||
"category": "preference",
|
||||
"content": "پاسخها خلاصه، سریع، دقیق، ساختاریافته و با بولتپوینتهای خوانا ارسال شوند.",
|
||||
"content_en": "Responses should be concise, well-structured, and easy to read.",
|
||||
},
|
||||
"tz_tehran": {
|
||||
"key": "preferred_timezone",
|
||||
"category": "preference",
|
||||
"content": "منطقه زمانی کاربر Asia/Tehran (ایران) است و زمانبندیها بر اساس این منطقه انجام شوند.",
|
||||
"content_en": "User timezone is Asia/Tehran.",
|
||||
},
|
||||
"php_pref": {
|
||||
"key": "preferred_tech_stack",
|
||||
"category": "preference",
|
||||
"content": "ترجیح زبان برنامهنویسی و پشته توسعه دهنده PHP مدرن (PHP 8.x) است.",
|
||||
"content_en": "Developer prefers modern PHP 8.x tech stack.",
|
||||
},
|
||||
},
|
||||
"global": {
|
||||
"user_isolation": {
|
||||
"key": "user_isolation_security",
|
||||
"category": "rule",
|
||||
"content": "کاربران عادی به جز مدیر فقط حق کار درون دایرکتوری اختصاصی پروژه خود (/root/projects/{user_id}/...) را دارند و هرگز نباید پرامپتها یا دادههای سیستمی به آنها افشا شود.",
|
||||
"content_en": "Non-admin users are strictly isolated to their own project directories.",
|
||||
},
|
||||
"caddy_ssl": {
|
||||
"key": "server_domain_caddy",
|
||||
"category": "rule",
|
||||
"content": "تمام سرویسهای وب و سابدامینهای *.msa.artacloud.ir باید با Caddy با SSL خودکار تنظیم و فعال شوند.",
|
||||
"content_en": "All web services and subdomains are routed through Caddy with automatic SSL.",
|
||||
},
|
||||
"hierarchy_rule": {
|
||||
"key": "precedence_hierarchy",
|
||||
"category": "rule",
|
||||
"content": "سلسلهمراتب قطعی اولویت: ۱. قوانین عمومی سیستم ۲. خاطرات و تصمیمات اختصاصی پروژه ۳. ترجیحات کلی کاربر.",
|
||||
"content_en": "Strict precedence: 1. Global rules, 2. Project memory, 3. User preferences.",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def build_memory_add_menu(chat_id: int, view_type: str = "project") -> tuple[str, InlineKeyboardMarkup]:
|
||||
"""Builds interactive memory creation / template guide menu with quick presets and copyable command."""
|
||||
from memory_manager import memory_manager
|
||||
session = session_manager.get_or_create(chat_id)
|
||||
curr_proj = session_manager.get_current_project(chat_id)
|
||||
is_fa = (session.language or "").lower() in ("fa", "farsi", "persian", "🇮🇷 persian / farsi (فارسی)")
|
||||
is_admin_user = settings.is_admin(chat_id)
|
||||
|
||||
proj_name = curr_proj.name if curr_proj else "default"
|
||||
|
||||
if view_type == "global" and not is_admin_user:
|
||||
view_type = "project" if curr_proj else "user"
|
||||
if view_type not in ("project", "user", "global"):
|
||||
view_type = "project" if curr_proj else "user"
|
||||
|
||||
if is_fa:
|
||||
type_labels = {
|
||||
"project": f"📁 پروژه اختصاصی (<code>{escape_html(proj_name)}</code>)",
|
||||
"user": "👤 ترجیحات و مشخصات شخصی من (سراسری)",
|
||||
"global": "🌐 قوانین عمومی سیستم (کل سرور)",
|
||||
}
|
||||
text = (
|
||||
f"🧠 <b>افزودن خاطره به حافظه هوش مصنوعی (Add Memory)</b>\n\n"
|
||||
f"• 🎯 <b>بخش انتخابی:</b> {type_labels.get(view_type, view_type)}\n\n"
|
||||
f"💡 <b>روشهای ثبت خاطره:</b>\n\n"
|
||||
f"📌 <b>۱. ثبت سریع با الگوهای آماده (با یک کلیک):</b>\n"
|
||||
f"با لمس هر یک از دکمههای زیر، خاطره استاندارد بلافاصله در این بخش ذخیره میشود.\n\n"
|
||||
f"📌 <b>۲. ثبت دستی با دستور مستقیم (کپی و ویرایش):</b>\n"
|
||||
f"<code>/memory add {view_type} <کلید> | <متن خاطره یا قانون></code>\n\n"
|
||||
f"<b>مثال:</b>\n"
|
||||
f"• <code>/memory add {view_type} code_style | کدهای پایتون و PHP به صورت ماژولار و تمیز نوشته شوند</code>\n\n"
|
||||
f"📌 <b>۳. آموزش مستقیم در چت با هوش مصنوعی:</b>\n"
|
||||
f"در حین گفتگو بنویسید: <i>«این نکته رو در حافظه ثبت کن: پورت دیتابیس ۵۴۳۲ است»</i> تا خودکار به خاطر بسپارد."
|
||||
)
|
||||
else:
|
||||
type_labels = {
|
||||
"project": f"📁 Active Project (<code>{escape_html(proj_name)}</code>)",
|
||||
"user": "👤 Personal Profile / Preferences",
|
||||
"global": "🌐 Global System Rules",
|
||||
}
|
||||
text = (
|
||||
f"🧠 <b>Add AI Long-Term Memory</b>\n\n"
|
||||
f"• 🎯 <b>Target Tier:</b> {type_labels.get(view_type, view_type)}\n\n"
|
||||
f"💡 <b>Methods to Add Memory:</b>\n\n"
|
||||
f"📌 <b>1. One-Click Quick Presets:</b>\n"
|
||||
f"Click any button below to instantly save standard rules or preferences.\n\n"
|
||||
f"📌 <b>2. Manual Command:</b>\n"
|
||||
f"<code>/memory add {view_type} <key> | <content></code>\n\n"
|
||||
f"<b>Example:</b>\n"
|
||||
f"• <code>/memory add {view_type} code_style | Write clean modular code</code>\n\n"
|
||||
f"📌 <b>3. Direct Chat with AI:</b>\n"
|
||||
f"Simply tell AI in chat: <i>'Remember that PostgreSQL port is 5432'</i>."
|
||||
)
|
||||
|
||||
keyboard = []
|
||||
|
||||
# 1. Tier selection tabs
|
||||
t_proj = f"📁 پروژه ({proj_name[:10]}) ✓" if view_type == "project" else f"📁 پروژه ({proj_name[:10]})"
|
||||
t_user = "👤 کاربر (من) ✓" if view_type == "user" else "👤 کاربر (من)"
|
||||
t_glob = "🌐 عمومی ✓" if view_type == "global" else "🌐 عمومی"
|
||||
if not is_fa:
|
||||
t_proj = "📁 Project ✓" if view_type == "project" else "📁 Project"
|
||||
t_user = "👤 User ✓" if view_type == "user" else "👤 User"
|
||||
t_glob = "🌐 Global ✓" if view_type == "global" else "🌐 Global"
|
||||
|
||||
tab_row = [
|
||||
InlineKeyboardButton(t_proj, callback_data="mem_add_tab:project"),
|
||||
InlineKeyboardButton(t_user, callback_data="mem_add_tab:user"),
|
||||
]
|
||||
if is_admin_user:
|
||||
tab_row.append(InlineKeyboardButton(t_glob, callback_data="mem_add_tab:global"))
|
||||
keyboard.append(tab_row)
|
||||
|
||||
# 2. Preset buttons based on view_type
|
||||
if view_type == "project":
|
||||
if is_fa:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🐘 اولویت با PHP مدرن و Caddy", callback_data="mem_add_preset:project:php_caddy"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🛡️ اجرای تست و اعتبارسنجی کامل", callback_data="mem_add_preset:project:qa_tests"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("📁 تمیزی و سازماندهی کدها", callback_data="mem_add_preset:project:clean_code"),
|
||||
])
|
||||
else:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🐘 Prefer Modern PHP & Caddy", callback_data="mem_add_preset:project:php_caddy"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🛡️ Strict QA Testing & Audit", callback_data="mem_add_preset:project:qa_tests"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("📁 Clean Code & Standards", callback_data="mem_add_preset:project:clean_code"),
|
||||
])
|
||||
elif view_type == "user":
|
||||
if is_fa:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🇮🇷 پاسخها همیشه فارسی روان باشد", callback_data="mem_add_preset:user:lang_fa"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("📝 پاسخهای فشرده و ساختاریافته", callback_data="mem_add_preset:user:concise_style"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("⏰ منطقه زمانی Asia/Tehran", callback_data="mem_add_preset:user:tz_tehran"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🐘 ترجیح اولویت توسعه با PHP", callback_data="mem_add_preset:user:php_pref"),
|
||||
])
|
||||
else:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🇮🇷 Always Respond in Persian", callback_data="mem_add_preset:user:lang_fa"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("📝 Concise & Structured Style", callback_data="mem_add_preset:user:concise_style"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("⏰ Timezone Asia/Tehran", callback_data="mem_add_preset:user:tz_tehran"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🐘 Prefer PHP Stack", callback_data="mem_add_preset:user:php_pref"),
|
||||
])
|
||||
elif view_type == "global" and is_admin_user:
|
||||
if is_fa:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔒 قرنطینه و تفکیک امنیتی کاربران", callback_data="mem_add_preset:global:user_isolation"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🌐 رورسپروکسی Caddy و SSL خودکار", callback_data="mem_add_preset:global:caddy_ssl"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("⚖️ رعایت سلسلهمراتب ۳ سطحی حافظه", callback_data="mem_add_preset:global:hierarchy_rule"),
|
||||
])
|
||||
else:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔒 User Isolation & Security", callback_data="mem_add_preset:global:user_isolation"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🌐 Caddy SSL Reverse Proxy", callback_data="mem_add_preset:global:caddy_ssl"),
|
||||
])
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("⚖️ Strict Memory Precedence", callback_data="mem_add_preset:global:hierarchy_rule"),
|
||||
])
|
||||
|
||||
# 3. Navigation row
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🔙 لیست خاطرات" if is_fa else "🔙 Memory List", callback_data=f"mem_tab:{view_type}:0"),
|
||||
InlineKeyboardButton("🏠 منوی اصلی" if is_fa else "🏠 Main Dashboard", callback_data="btn_dashboard"),
|
||||
])
|
||||
|
||||
return text, InlineKeyboardMarkup(keyboard)
|
||||
|
||||
|
||||
def build_tasks_menu(chat_id: int, page: int = 0) -> tuple[str, InlineKeyboardMarkup]:
|
||||
"""Builds interactive Scheduled Tasks manager dashboard with pagination and status buttons."""
|
||||
session = session_manager.get_or_create(chat_id)
|
||||
@@ -1895,11 +2125,12 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
f"• <code>/lang [زبان]</code> - تغییر زبان پاسخدهی (مثلاً <code>/lang fa</code>)\n"
|
||||
f"• <code>/effort [low|med|high]</code> - تنظیم عمق تفکر استدلالی\n"
|
||||
f"<b>🧠 حافظه بلندمدت هوش مصنوعی (AI Memory):</b>\n"
|
||||
f"• <code>/memory</code> - کنترلپنل تعاملی حافظه هوشمند، مشاهده و پاکسازی خاطرات\n"
|
||||
f"• <code>/memory</code> - کنترلپنل تعاملی حافظه هوشمند، دکمههای افزودن، مشاهده و پاکسازی خاطرات\n"
|
||||
f"• <code>/memory add [project|user|global] کلید | متن</code> - افزودن مستقیم خاطره جدید\n"
|
||||
f"• <code>/memory global</code> - مشاهده قوانین و خاطرات عمومی کل سیستم\n"
|
||||
f"• <code>/memory private</code> - مشاهده خاطرات اختصاصی و شخصی شما\n"
|
||||
f"• <code>/memory clear</code> - پاکسازی خاطرات اختصاصی شما\n"
|
||||
f"• <i>هوش مصنوعی در طول مکالمات، نکات کلیدی و ترجیحات شما را به صورت خودکار به خاطر میسپارد!</i>\n\n"
|
||||
f"• <i>امکان افزودن با ۱ کلیک از طریق دکمه «➕ افزودن خاطره» در پنل حافظه و منوی پروژهها فراهم است.</i>\n\n"
|
||||
f"<b>👑 مدیریت کاربران و دعوتها (ویژه مدیر):</b>\n"
|
||||
f"• <code>/users</code> - پنل تعاملی مدیریت کاربران و لیست مجاز\n"
|
||||
f"• <code>/invite <user_id></code> - دعوت و اعطای مستقیم دسترسی به کاربر\n"
|
||||
@@ -5340,6 +5571,55 @@ async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
except Exception:
|
||||
await query.message.reply_html(text, reply_markup=markup)
|
||||
|
||||
elif data.startswith("mem_add_menu:") or data.startswith("mem_add_tab:"):
|
||||
parts = data.split(":")
|
||||
v_type = parts[1] if len(parts) > 1 else "project"
|
||||
if v_type == "global" and not is_admin_user:
|
||||
await query.answer("🚫 افزودن حافظه عمومی فقط مختص مدیر سیستم است." if is_fa else "🚫 Global memory restricted to administrators.", show_alert=True)
|
||||
v_type = "project" if session_manager.get_current_project(chat_id) else "user"
|
||||
text, markup = build_memory_add_menu(chat_id, view_type=v_type)
|
||||
try:
|
||||
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup)
|
||||
except Exception:
|
||||
await query.message.reply_html(text, reply_markup=markup)
|
||||
|
||||
elif data.startswith("mem_add_preset:"):
|
||||
_, target_type, preset_name = data.split(":", 2)
|
||||
if target_type == "global" and not is_admin_user:
|
||||
await query.answer("🚫 دسترسی غیرمجاز!" if is_fa else "🚫 Permission denied!", show_alert=True)
|
||||
return
|
||||
|
||||
from memory_manager import memory_manager
|
||||
curr_p = session_manager.get_current_project(chat_id)
|
||||
p_name = curr_p.name if curr_p else "default"
|
||||
|
||||
preset_data = MEMORY_PRESETS.get(target_type, {}).get(preset_name)
|
||||
if not preset_data:
|
||||
await query.answer("❌ الگوی مورد نظر یافت نشد." if is_fa else "❌ Preset not found.", show_alert=True)
|
||||
return
|
||||
|
||||
try:
|
||||
item, is_created = memory_manager.save_or_update(
|
||||
type_=target_type,
|
||||
key=preset_data["key"],
|
||||
content=preset_data["content"] if is_fa else preset_data.get("content_en", preset_data["content"]),
|
||||
user_id=chat_id,
|
||||
project_name=p_name if target_type == "project" else None,
|
||||
category=preset_data.get("category", "general"),
|
||||
importance=5 if target_type == "global" else 3,
|
||||
created_by=chat_id,
|
||||
)
|
||||
action_str = "ثبت شد" if is_created else "بهروزرسانی شد"
|
||||
await query.answer(f"✅ خاطره «{item.key}» با موفقیت {action_str}!" if is_fa else f"✅ Memory '{item.key}' saved!", show_alert=True)
|
||||
except Exception as e:
|
||||
await query.answer(f"⚠️ خطا در ثبت خاطره: {e}", show_alert=True)
|
||||
|
||||
text, markup = build_memory_menu(chat_id, view_type=target_type, page=0)
|
||||
try:
|
||||
await query.edit_message_text(text, parse_mode=constants.ParseMode.HTML, reply_markup=markup)
|
||||
except Exception:
|
||||
await query.message.reply_html(text, reply_markup=markup)
|
||||
|
||||
elif data == "btn_tasks_menu":
|
||||
text, markup = build_tasks_menu(chat_id, page=0)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user