From 5b434abd06271f578034a02a4dbeb471d3eb1890 Mon Sep 17 00:00:00 2001 From: Cailean Finn Date: Sun, 10 May 2026 18:46:51 +0100 Subject: [PATCH] plain url input accepted --- README.md | 1 + __pycache__/bot.cpython-314.pyc | Bin 0 -> 22197 bytes bot.py | 36 +++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 __pycache__/bot.cpython-314.pyc diff --git a/README.md b/README.md index b70a061..ed0d550 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ python main.py The bot listens for commands: - `/op ` — parse an opportunity - `/ev ` — parse an event +- If you send a URL directly in chat, the bot will ask whether to process it as an event or an opportunity using buttons. If you paste text (instead of sending a URL), the bot will parse it and when you click Save it will prompt you for a source URL (or you can `/skip`). diff --git a/__pycache__/bot.cpython-314.pyc b/__pycache__/bot.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17ade3bff3cafd65d8290d748564e2bde7a88073 GIT binary patch literal 22197 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 bool: + return bool(re.match(r'^https?://\S+$', text.strip())) + + +def build_url_choice_keyboard(url: str): + return InlineKeyboardMarkup([ + [InlineKeyboardButton("📅 Process as Event", callback_data='choose_type:event')], + [InlineKeyboardButton("📋 Process as Opportunity", callback_data='choose_type:opportunity')], + ]) + + def build_entry_summary(data, entry_type, saved=False): if entry_type == "event": event_datetime = data.get('date_time') or data.get('datetime') @@ -182,7 +194,8 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): "Welcome! I can extract arts opportunities and events.\n\n" "📋 **Commands:**\n" "/op - Extract an opportunity\n" - "/ev - Extract an event" + "/ev - Extract an event\n\n" + "You can also send a URL directly and I will ask whether to process it as an event or opportunity." ) async def handle_opportunity(update: Update, context: ContextTypes.DEFAULT_TYPE): @@ -230,6 +243,15 @@ async def handle_followup_text(update: Update, context: ContextTypes.DEFAULT_TYP return if not context.user_data.get('awaiting_save_url'): + text = (update.message.text or '').strip() + if not text or not is_http_url(text): + return + + context.user_data['pending_url_to_process'] = text + await update.message.reply_text( + "What should I do with this URL?", + reply_markup=build_url_choice_keyboard(text) + ) return text = update.message.text.strip() @@ -257,6 +279,18 @@ async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() + if query.data.startswith('choose_type:'): + pending_url = context.user_data.get('pending_url_to_process') + if not pending_url: + await query.edit_message_text("❌ I couldn't find a pending URL to process.") + return + + entry_type = query.data.split(':', 1)[1] + context.user_data['pending_url_to_process'] = None + await query.edit_message_text(f"📥 Queued URL for {entry_type} processing...") + await task_queue.put((update, context, pending_url, entry_type, 'url')) + return + if query.data == 'save_db': data = context.user_data.get('last_extracted') entry_type = context.user_data.get('last_entry_type', 'opportunity')