diff --git a/services/telegram_bot_service.py b/services/telegram_bot_service.py index 3c5ca4c..2125637 100644 --- a/services/telegram_bot_service.py +++ b/services/telegram_bot_service.py @@ -567,8 +567,8 @@ class TrendTelegramBot: chat_id = query.message.chat_id try: await query.edit_message_text("⏳ 正在處理,請稍候...") - except Exception: - pass + except Exception as _e: + logger.warning(f"[訊息編輯失敗,略過] {_e}") import threading as _t _t.Thread( target=self._forward_cmd_to_openclaw, @@ -585,41 +585,48 @@ class TrendTelegramBot: InlineKeyboardButton("🔙 返回主選單", callback_data="menu:main") ]]) ) - except Exception: - pass + except Exception as _e: + logger.warning(f"[訊息編輯失敗,略過] {_e}") async def _handle_await_callback(self, query, await_type: str, context): """處理所有 await: 類型的按鈕,設定 waiting_for 狀態並提示用戶輸入""" - prompts = { - 'date_range_sales': ('📅 業績查詢 — 指定日期區間', '請輸入日期區間\n格式:YYYY/MM/DD-YYYY/MM/DD\n例如:2026/04/01-2026/04/07'), - 'date_top': ('📅 商品排行 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), - 'date_competitor': ('📅 競品報告 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), - 'date_ppt_daily': ('📅 日報簡報 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), - 'date_ppt_monthly': ('📅 月報簡報 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), - 'date_ppt_vendor': ('📅 廠商簡報 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), - 'date_trend_month': ('📅 月份趨勢 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), - 'date_trend_year': ('📅 年度趨勢 — 指定年份', '請輸入年份\n格式:YYYY\n例如:2026'), - 'date_trend_quarter':('📅 季度趨勢 — 指定季度', '請輸入季度\n格式:YYYY/Q(Q=1~4)\n例如:2026/2'), - 'goal_daily': ('🎯 日目標設定', '請輸入日目標金額(元,純數字)\n例如:500000'), - 'goal_monthly': ('🎯 月目標設定', '請輸入月目標金額(元,純數字)\n例如:15000000'), - 'goal_quarterly': ('🎯 季目標設定', '請輸入季目標金額(元,純數字)\n例如:45000000'), - 'goal_half': ('🎯 半年目標設定', '請輸入半年目標金額(元,純數字)\n例如:90000000'), - 'goal_yearly': ('🎯 年目標設定', '請輸入年目標金額(元,純數字)\n例如:180000000'), - 'promo_range': ('🎉 促銷效益追蹤', '請輸入促銷日期區間\n格式:YYYY/MM/DD-YYYY/MM/DD\n例如:2026/04/01-2026/04/07'), - 'search_compare': ('🔍 競品關鍵字比價', '請輸入商品關鍵字\n例如:防曬乳 SPF50'), - } - if await_type not in prompts: - await query.answer(f"未知類型:{await_type}", show_alert=True) - return - title, hint = prompts[await_type] - context.user_data['waiting_for'] = await_type - await query.edit_message_text( - f"*{title}*\n\n{hint}\n\n請直接在對話框輸入:", - parse_mode='Markdown', - reply_markup=InlineKeyboardMarkup([[ - InlineKeyboardButton("❌ 取消", callback_data="menu:main") - ]]) - ) + try: + prompts = { + 'date_range_sales': ('📅 業績查詢 — 指定日期區間', '請輸入日期區間\n格式:YYYY/MM/DD-YYYY/MM/DD\n例如:2026/04/01-2026/04/07'), + 'date_top': ('📅 商品排行 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), + 'date_competitor': ('📅 競品報告 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), + 'date_ppt_daily': ('📅 日報簡報 — 指定日期', '請輸入日期\n格式:YYYY/MM/DD\n例如:2026/04/25'), + 'date_ppt_monthly': ('📅 月報簡報 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), + 'date_ppt_vendor': ('📅 廠商簡報 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), + 'date_trend_month': ('📅 月份趨勢 — 指定月份', '請輸入月份\n格式:YYYY/MM\n例如:2026/04'), + 'date_trend_year': ('📅 年度趨勢 — 指定年份', '請輸入年份\n格式:YYYY\n例如:2026'), + 'date_trend_quarter':('📅 季度趨勢 — 指定季度', '請輸入季度\n格式:YYYY/Q(Q=1~4)\n例如:2026/2'), + 'goal_daily': ('🎯 日目標設定', '請輸入日目標金額(元,純數字)\n例如:500000'), + 'goal_monthly': ('🎯 月目標設定', '請輸入月目標金額(元,純數字)\n例如:15000000'), + 'goal_quarterly': ('🎯 季目標設定', '請輸入季目標金額(元,純數字)\n例如:45000000'), + 'goal_half': ('🎯 半年目標設定', '請輸入半年目標金額(元,純數字)\n例如:90000000'), + 'goal_yearly': ('🎯 年目標設定', '請輸入年目標金額(元,純數字)\n例如:180000000'), + 'promo_range': ('🎉 促銷效益追蹤', '請輸入促銷日期區間\n格式:YYYY/MM/DD-YYYY/MM/DD\n例如:2026/04/01-2026/04/07'), + 'search_compare': ('🔍 競品關鍵字比價', '請輸入商品關鍵字\n例如:防曬乳 SPF50'), + } + if await_type not in prompts: + await query.answer(f"未知類型:{await_type}", show_alert=True) + return + title, hint = prompts[await_type] + context.user_data['waiting_for'] = await_type + await query.edit_message_text( + f"*{title}*\n\n{hint}\n\n請直接在對話框輸入:", + parse_mode='Markdown', + reply_markup=InlineKeyboardMarkup([[ + InlineKeyboardButton("❌ 取消", callback_data="menu:main") + ]]) + ) + except Exception as e: + logger.error(f"[_handle_await_callback] 處理失敗: {e}", exc_info=True) + try: + await query.answer("❌ 處理失敗,請重試", show_alert=True) + except Exception: + pass def _forward_cmd_to_openclaw(self, cmd: str, arg: str, chat_id: int): """轉發 cmd:* 指令到 OpenClaw Flask 內部 API""" @@ -638,53 +645,60 @@ class TrendTelegramBot: async def _handle_main_menu_callback(self, query, data: str): """處理主選單回調 - 完整功能菜單系統""" - key = data[5:] # 移除 'menu:' 前綴 - - titles = { - 'sales': '📊 *業績查詢* — 選擇日期或直接輸入', - 'products': '🏆 *商品廠商* — 選擇查詢範圍', - 'goals': '🎯 *目標管理* — 查看或設定業績目標', - 'analysis': '📈 *智能分析* — 選擇分析類型', - 'reports': '📄 *簡報報表* — 選擇報告類型', - 'market': '🌐 *市場情報* — 即時資訊', - 'competitor': '📊 *競品比價日報* — 選擇分析日期', - 'competitor_ppt': '📄 *競品比價簡報* — 選擇時間範圍', - 'category': '🗂 *分類業績鑽取* — 點選分類深入分析', - 'trend': '📈 *業績趨勢* — 選擇時間範圍', - } - - # 生成子選單 - if key == 'sales': - keyboard = self._get_sales_submenu() - elif key == 'products': - keyboard = self._get_products_submenu() - elif key == 'goals': - keyboard = self._get_goals_submenu() - elif key == 'analysis': - keyboard = self._get_analysis_submenu() - elif key == 'reports': - keyboard = self._get_reports_submenu() - elif key == 'market': - keyboard = self._get_market_submenu() - elif key == 'competitor': - keyboard = self._get_competitor_submenu() - elif key == 'competitor_ppt': - keyboard = self._get_competitor_ppt_submenu() - elif key == 'category': - keyboard = self._get_category_submenu() - elif key == 'trend': - keyboard = self._get_trend_submenu() - else: - # 未知選單,返回主選單 - keyboard = self._get_main_menu_keyboard() - key = 'main' - titles[key] = '👋 *MOMO 趨勢助手 Bot* — 請選擇功能類別' - - await query.edit_message_text( - titles.get(key, '請選擇'), - parse_mode='Markdown', - reply_markup=InlineKeyboardMarkup(keyboard) - ) + try: + key = data[5:] # 移除 'menu:' 前綴 + + titles = { + 'sales': '📊 *業績查詢* — 選擇日期或直接輸入', + 'products': '🏆 *商品廠商* — 選擇查詢範圍', + 'goals': '🎯 *目標管理* — 查看或設定業績目標', + 'analysis': '📈 *智能分析* — 選擇分析類型', + 'reports': '📄 *簡報報表* — 選擇報告類型', + 'market': '🌐 *市場情報* — 即時資訊', + 'competitor': '📊 *競品比價日報* — 選擇分析日期', + 'competitor_ppt': '📄 *競品比價簡報* — 選擇時間範圍', + 'category': '🗂 *分類業績鑽取* — 點選分類深入分析', + 'trend': '📈 *業績趨勢* — 選擇時間範圍', + } + + # 生成子選單 + if key == 'sales': + keyboard = self._get_sales_submenu() + elif key == 'products': + keyboard = self._get_products_submenu() + elif key == 'goals': + keyboard = self._get_goals_submenu() + elif key == 'analysis': + keyboard = self._get_analysis_submenu() + elif key == 'reports': + keyboard = self._get_reports_submenu() + elif key == 'market': + keyboard = self._get_market_submenu() + elif key == 'competitor': + keyboard = self._get_competitor_submenu() + elif key == 'competitor_ppt': + keyboard = self._get_competitor_ppt_submenu() + elif key == 'category': + keyboard = self._get_category_submenu() + elif key == 'trend': + keyboard = self._get_trend_submenu() + else: + # 未知選單,返回主選單 + keyboard = self._get_main_menu_keyboard() + key = 'main' + titles[key] = '👋 *MOMO 趨勢助手 Bot* — 請選擇功能類別' + + await query.edit_message_text( + titles.get(key, '請選擇'), + parse_mode='Markdown', + reply_markup=InlineKeyboardMarkup(keyboard) + ) + except Exception as e: + logger.error(f"[_handle_main_menu_callback] 處理失敗: {e}", exc_info=True) + try: + await query.answer("❌ 處理失敗,請重試", show_alert=True) + except Exception: + pass def _get_sales_submenu(self): """業績查詢子選單""" @@ -1531,42 +1545,42 @@ class TrendTelegramBot: """Get suggestions based on query type (Traditional Chinese)""" suggestions = { "sales analysis": [ - "Check today's sales performance", - "View weekly sales trend", - "Sales by category analysis", - "Compare with previous period" + "查看今日業績表現", + "查看週業績趨勢", + "品類銷售分析", + "與前期對比" ], "product analysis": [ - "Top selling products today", - "Brand performance analysis", - "Product health check", - "Inventory forecast" + "今日熱銷商品", + "品牌績效分析", + "商品健康檢查", + "庫存預測" ], "market intelligence": [ - "Latest market news", - "Competitor pricing analysis", - "Trending keywords", - "Industry insights" + "最新市場動態", + "競品定價分析", + "熱門關鍵字", + "產業洞察" ], "report generation": [ - "Daily sales report", - "Weekly performance summary", - "Competitive analysis PPT", - "Strategic planning report" + "每日業績報告", + "週績效摘要", + "競品分析簡報", + "策略規劃報告" ], "comparative analysis": [ - "Compare with competitors", - "Period over period comparison", - "Category performance comparison", - "Brand vs brand analysis" + "與競品比較", + "期間對比分析", + "品類績效比較", + "品牌對比分析" ] } - + return suggestions.get(query_type, [ - "View main menu options", - "Check sales dashboard", - "Product analysis", - "Market intelligence" + "查看主選單", + "查看業績儀表板", + "商品分析", + "市場情報" ]) async def _process_await_input(self, update, context, await_type: str, text: str):