weavebot-telegram
Version:
Generic Telegram bot framework with command registration
1 lines • 32.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/bot.ts"],"sourcesContent":["import { Telegraf, Context } from 'telegraf';\nimport ContentProcessor, { \n ProcessorInput, \n ProcessorResult, \n CommandHandler,\n CommandContext,\n CommandResult,\n defaultLogger\n} from 'weavebot-core';\n\nexport interface TelegramBotConfig {\n botToken: string;\n authorizedAdmins?: string[];\n processor?: ContentProcessor;\n enableLogging?: boolean;\n}\n\nexport class TelegramBot {\n private bot: Telegraf;\n private processor: ContentProcessor;\n private config: TelegramBotConfig;\n\n constructor(config: TelegramBotConfig) {\n this.config = config;\n this.bot = new Telegraf(config.botToken);\n this.processor = config.processor || new ContentProcessor();\n\n this.setupCommands();\n this.setupErrorHandling();\n\n if (config.enableLogging !== false) {\n this.setupLogging();\n }\n }\n\n private setupCommands() {\n // Help command\n this.bot.command('help', async (ctx) => {\n await this.handleHelpCommand(ctx);\n });\n\n // Event processing command\n this.bot.command('event', async (ctx) => {\n await this.handleEventCommand(ctx);\n });\n\n // Update processing command\n this.bot.command('update', async (ctx) => {\n await this.handleUpdateCommand(ctx);\n });\n\n // Link processing command\n this.bot.command('link', async (ctx) => {\n await this.handleLinkCommand(ctx);\n });\n\n // Status command\n this.bot.command('status', async (ctx) => {\n await this.handleStatusCommand(ctx);\n });\n\n // Admin commands\n this.bot.command('init', async (ctx) => {\n await this.handleInitCommand(ctx);\n });\n\n this.bot.command('weekly_weave', async (ctx) => {\n await this.handleWeeklyWeaveCommand(ctx);\n });\n }\n\n private setupErrorHandling() {\n this.bot.catch((err, ctx) => {\n defaultLogger.error('Telegram bot error', { \n error: err instanceof Error ? err.message : String(err),\n userId: ctx.from?.id?.toString(),\n chatId: ctx.chat?.id?.toString() \n });\n\n ctx.reply('❌ An unexpected error occurred. Please try again later.')\n .catch(() => {}); // Ignore reply errors\n });\n }\n\n private setupLogging() {\n this.bot.use(async (ctx, next) => {\n const start = Date.now();\n const userId = ctx.from?.id?.toString();\n const chatId = ctx.chat?.id?.toString();\n const messageText = 'text' in ctx.message! ? ctx.message.text : '[non-text]';\n\n defaultLogger.info('Telegram message received', {\n userId,\n chatId,\n messageText: messageText?.substring(0, 100)\n });\n\n await next();\n\n const duration = Date.now() - start;\n defaultLogger.info('Telegram message processed', {\n userId,\n chatId,\n duration\n });\n });\n }\n\n // Command handlers\n private async handleHelpCommand(ctx: Context) {\n const helpMessage = `🤖 *WeaveBot Help*\n\n*Available Commands:*\n\n🎉 \\`/event <URL>\\` - Extract event information from a web page\n Example: \\`/event https://www.meetup.com/some-event/\\`\n\n📰 \\`/update <URL or text>\\` - Process an update or article\n Examples: \n \\`/update https://blog.example.com/article\\`\n \\`/update This is a community announcement...\\`\n\n🔗 \\`/link <URL>\\` - Save a link with a one-sentence summary\n Example: \\`/link https://github.com/some-project\\`\n\n📊 \\`/status\\` - Show bot status and configuration\n\n📬 \\`/weekly_weave\\` - Generate weekly newsletter (Admin only)\n\n❓ \\`/help\\` - Show this help message\n\n*Supported Platforms:*\n• Meetup.com\n• Eventbrite.com \n• Facebook Events\n• Luma.com\n• Most event websites\n• Blog articles and news sites\n\n*How it works:*\n1. Send a URL with \\`/event\\` or \\`/update\\`\n2. WeaveBot scrapes the page content\n3. AI extracts structured information\n4. Data is saved to configured storage\n5. You get a formatted summary\n\n*Tips:*\n• Make sure URLs are publicly accessible\n• The bot works best with pages that have clear event details\n• Processing may take 10-30 seconds for complex pages\n\nNeed help? Contact the bot administrator.`;\n\n await ctx.reply(helpMessage, { parse_mode: 'Markdown' });\n }\n\n private async handleEventCommand(ctx: Context) {\n const userId = ctx.from?.id?.toString();\n const chatId = ctx.chat?.id?.toString();\n\n if (!userId || !chatId) {\n return;\n }\n\n const text = 'text' in ctx.message! ? ctx.message.text : '';\n const args = text.split(' ').slice(1);\n\n if (args.length === 0) {\n await ctx.reply(\n '🤖 Please provide a URL after the /event command.\\n\\n' +\n 'Example: `/event https://www.meetup.com/some-event/`',\n { parse_mode: 'Markdown' }\n );\n return;\n }\n\n const url = args[0];\n\n if (!this.isValidUrl(url)) {\n await ctx.reply(\n '❌ That doesn\\'t look like a valid URL. Please provide a full URL starting with http or https.'\n );\n return;\n }\n\n // Add eyes emoji reaction to indicate processing\n await ctx.react([{ type: \"emoji\", emoji: \"👀\" }]).catch(() => {});\n\n try {\n const result = await this.processor.process({\n type: 'url',\n data: url,\n schema: 'event',\n options: {\n timeout: 60000 // Increase timeout to 60 seconds\n }\n }, { userId, chatId });\n\n if (result.success && result.data) {\n // Store in configured storage and get the record ID\n const recordId = await this.storeData(result.data, 'event');\n \n const message = this.formatEventMessage(result.data, recordId);\n await ctx.reply(message, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n\n // Remove the eyes emoji and add checkmark\n await ctx.react([{ type: \"emoji\", emoji: \"👍\" }]).catch(() => {});\n } else {\n throw new Error(result.error?.message || 'Processing failed');\n }\n\n } catch (error) {\n // Remove eyes emoji and add error reaction\n await ctx.react([{ type: \"emoji\", emoji: \"👎\" }]).catch(() => {});\n \n const errorMessage = this.formatErrorMessage(\n (error as Error).message,\n url\n );\n \n await ctx.reply(errorMessage, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n }\n }\n\n private async handleUpdateCommand(ctx: Context) {\n const userId = ctx.from?.id?.toString();\n const chatId = ctx.chat?.id?.toString();\n\n if (!userId || !chatId) {\n return;\n }\n\n const text = 'text' in ctx.message! ? ctx.message.text : '';\n const args = text.split(' ').slice(1);\n\n if (args.length === 0) {\n await ctx.reply(\n '🤖 Please provide a URL or text after the /update command.\\n\\n' +\n 'Examples:\\n' +\n '`/update https://blog.example.com/article`\\n' +\n '`/update This is a community announcement...`',\n { parse_mode: 'Markdown' }\n );\n return;\n }\n\n const input = args.join(' ');\n const isUrl = this.isValidUrl(input);\n\n // Add eyes emoji reaction to indicate processing\n await ctx.react([{ type: \"emoji\", emoji: \"👀\" }]).catch(() => {});\n\n try {\n const result = await this.processor.process({\n type: isUrl ? 'url' : 'text',\n data: input,\n schema: 'update'\n }, { userId, chatId });\n\n if (result.success && result.data) {\n // Store in configured storage and get the record ID\n const recordId = await this.storeData(result.data, 'update');\n \n const message = this.formatUpdateMessage(result.data, recordId);\n await ctx.reply(message, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n\n // Remove the eyes emoji and add checkmark\n await ctx.react([{ type: \"emoji\", emoji: \"👍\" }]).catch(() => {});\n } else {\n throw new Error(result.error?.message || 'Processing failed');\n }\n\n } catch (error) {\n // Remove eyes emoji and add error reaction\n await ctx.react([{ type: \"emoji\", emoji: \"👎\" }]).catch(() => {});\n \n const errorMessage = this.formatErrorMessage(\n (error as Error).message,\n isUrl ? input : undefined\n );\n \n await ctx.reply(errorMessage, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n }\n }\n\n private async handleLinkCommand(ctx: Context) {\n const userId = ctx.from?.id?.toString();\n const chatId = ctx.chat?.id?.toString();\n\n if (!userId || !chatId) {\n return;\n }\n\n const text = 'text' in ctx.message! ? ctx.message.text : '';\n const args = text.split(' ').slice(1);\n\n if (args.length === 0) {\n await ctx.reply(\n '🔗 Please provide a URL after the /link command.\\n\\n' +\n 'Example: `/link https://example.com`',\n { parse_mode: 'Markdown' }\n );\n return;\n }\n\n const url = args[0];\n\n if (!this.isValidUrl(url)) {\n await ctx.reply(\n '❌ That doesn\\'t look like a valid URL. Please provide a full URL starting with http or https.'\n );\n return;\n }\n\n // Add eyes emoji reaction to indicate processing\n await ctx.react([{ type: \"emoji\", emoji: \"👀\" }]).catch(() => {});\n\n try {\n const result = await this.processor.process({\n type: 'url',\n data: url,\n schema: 'link',\n options: {\n timeout: 60000 // Increase timeout to 60 seconds\n }\n }, { userId, chatId });\n\n if (result.success && result.data) {\n // Store in configured storage and get the record ID\n const recordId = await this.storeData(result.data, 'link');\n \n const message = this.formatLinkMessage(result.data, recordId);\n await ctx.reply(message, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n\n // Remove the eyes emoji and add checkmark\n await ctx.react([{ type: \"emoji\", emoji: \"👍\" }]).catch(() => {});\n } else {\n throw new Error(result.error?.message || 'Processing failed');\n }\n\n } catch (error) {\n // Remove eyes emoji and add error reaction\n await ctx.react([{ type: \"emoji\", emoji: \"👎\" }]).catch(() => {});\n \n const errorMessage = this.formatErrorMessage(\n (error as Error).message,\n url\n );\n \n await ctx.reply(errorMessage, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n }\n }\n\n private async handleStatusCommand(ctx: Context) {\n const processors = this.processor.listProcessors();\n const storageAdapters = this.processor.listStorageAdapters();\n const schemas = this.processor.listSchemas();\n\n const status = `📊 *Bot Status*\n\n*Processors:* ${processors.length > 0 ? processors.join(', ') : 'None'}\n*Storage:* ${storageAdapters.length > 0 ? storageAdapters.join(', ') : 'None'}\n*Schemas:* ${schemas.length > 0 ? schemas.join(', ') : 'None'}\n\n*Bot Version:* 1.0.0\n*Status:* ✅ Running`;\n\n await ctx.reply(status, { parse_mode: 'Markdown' });\n }\n\n private async handleInitCommand(ctx: Context) {\n const userId = ctx.from?.id?.toString();\n\n // Check admin authorization\n if (this.config.authorizedAdmins && \n this.config.authorizedAdmins.length > 0 && \n !this.config.authorizedAdmins.includes(userId!)) {\n await ctx.reply('🔒 You are not authorized to initialize Airtable configuration.');\n return;\n }\n\n await ctx.reply('🔄 Initializing Airtable configuration...\\n\\nDiscovering tables and setting up configuration...');\n\n try {\n // Get the Airtable storage adapter\n const storageAdapters = this.processor.listStorageAdapters();\n if (storageAdapters.length === 0) {\n throw new Error('No Airtable storage adapter configured');\n }\n\n const storage = this.processor.getStorage(storageAdapters[0]);\n if (!storage || !('initializeSetup' in storage)) {\n throw new Error('Airtable storage adapter does not support initialization');\n }\n\n // Initialize and get setup\n const setup = await (storage as any).initializeSetup();\n \n // Apply the setup to the storage adapter\n (storage as any).applySetup(setup);\n\n // Save configuration to file\n await this.saveAirtableConfig(setup);\n\n let message = `✅ *Airtable Initialization Complete*\n\n📊 *Events Table*\n• ID: \\`${setup.eventsTable.id}\\`\n• View: \\`${setup.eventsTable.primaryViewId}\\`\n• Fields: ${setup.eventsTable.fields.length} configured\n\n📰 *Updates Table* \n• ID: \\`${setup.updatesTable.id}\\`\n• View: \\`${setup.updatesTable.primaryViewId}\\`\n• Fields: ${setup.updatesTable.fields.length} configured`;\n\n if (setup.linksTable) {\n message += `\n\n🔗 *Links Table*\n• ID: \\`${setup.linksTable.id}\\`\n• View: \\`${setup.linksTable.primaryViewId}\\`\n• Fields: ${setup.linksTable.fields.length} configured`;\n }\n\n message += `\n\n💾 Configuration saved to \\`airtable-config.json\\`\n\n🎉 WeaveBot is now ready to process events, updates, and links with working Airtable links!`;\n\n await ctx.reply(message, { parse_mode: 'Markdown' });\n\n } catch (error) {\n const errorMessage = this.formatErrorMessage(\n (error as Error).message,\n undefined\n );\n \n await ctx.reply(errorMessage, { \n parse_mode: 'Markdown',\n link_preview_options: { is_disabled: true }\n });\n }\n }\n\n private async handleWeeklyWeaveCommand(ctx: Context) {\n const userId = ctx.from?.id?.toString();\n\n // Check admin authorization\n if (this.config.authorizedAdmins && \n this.config.authorizedAdmins.length > 0 && \n !this.config.authorizedAdmins.includes(userId!)) {\n await ctx.reply('🔒 You are not authorized to generate newsletters.');\n return;\n }\n\n await ctx.reply(\n '📰 Newsletter generation is not yet implemented in the library version.\\n\\n' +\n 'This feature will be available in a future release.'\n );\n }\n\n private async saveAirtableConfig(setup: any): Promise<void> {\n try {\n const fs = await import('fs/promises');\n const path = await import('path');\n const configPath = path.join(process.cwd(), 'airtable-config.json');\n \n const configData = JSON.stringify(setup, null, 2);\n await fs.writeFile(configPath, configData, 'utf-8');\n \n defaultLogger.info('Airtable configuration saved', { path: configPath });\n } catch (error) {\n defaultLogger.error('Failed to save Airtable configuration', { error: (error as Error).message });\n throw new Error(`Failed to save configuration: ${(error as Error).message}`);\n }\n }\n\n // Utility methods\n private isValidUrl(string: string): boolean {\n try {\n new URL(string);\n return true;\n } catch (_) {\n return false;\n }\n }\n\n private formatEventMessage(event: any, recordId?: string): string {\n const airtableLink = recordId ? this.getAirtableRecordLink('Events', recordId) : null;\n \n let message = `✅ *Event Processed Successfully*\n\n*${event.title}*\n\n📅 *Date:* ${this.formatDate(event.startDateTime)}\n📍 *Location:* ${event.location?.venue || event.location?.address || 'TBD'}\n🏢 *Organizer:* ${event.organizer?.name || 'TBD'}\n🎟️ *Price:* ${event.ticketPrice?.isFree ? 'Free' : (event.ticketPrice?.amount ? `${event.ticketPrice.currency} ${event.ticketPrice.amount}` : 'TBD')}\n🌐 *Online:* ${event.isOnline ? 'Yes' : 'No'}\n\n📝 *Description:*\n${event.description?.substring(0, 300)}${event.description?.length > 300 ? '...' : ''}\n\n*Event saved to database* ✅`;\n \n if (airtableLink) {\n message += `\n\n[📊 View in Airtable](${airtableLink})`;\n }\n \n return message;\n }\n\n private formatUpdateMessage(update: any, recordId?: string): string {\n const airtableLink = recordId ? this.getAirtableRecordLink('Updates', recordId) : null;\n \n let message = `✅ *Update Processed Successfully*\n\n*${update.title}*\n\n👤 *Author:* ${update.author || 'Unknown'}\n📂 *Category:* ${update.category}\n⭐ *Relevance:* ${update.relevanceScore}/10\n\n📝 *Summary:*\n${update.summary}\n\n*Update saved to database* ✅`;\n \n if (airtableLink) {\n message += `\n\n[📊 View in Airtable](${airtableLink})`;\n }\n \n return message;\n }\n\n private formatLinkMessage(link: any, recordId?: string): string {\n const airtableLink = recordId ? this.getAirtableRecordLink('Links', recordId) : null;\n \n let message = `✅ *Link Saved Successfully*\n\n🔗 *URL:* ${link.url}\n\n📝 *Title:* ${link.title}\n\n💬 *Summary:* _${link.summary}_\n\n*Link saved to database* ✅`;\n \n if (airtableLink) {\n message += `\n\n[📊 View in Airtable](${airtableLink})`;\n }\n \n return message;\n }\n\n private formatErrorMessage(error: string, url?: string): string {\n let message = `❌ *Processing Failed*\\n\\n`;\n \n if (url) {\n message += `*URL:* ${url}\\n\\n`;\n }\n \n message += `*Error:* ${error}\\n\\n`;\n message += `🔧 *Troubleshooting:*\\n`;\n message += `• Make sure the URL is publicly accessible\\n`;\n message += `• Check if the page contains event/update information\\n`;\n message += `• Try again in a few moments\\n`;\n message += `• Contact administrator if the problem persists`;\n\n return message;\n }\n\n private formatDate(dateString: string): string {\n try {\n return new Date(dateString).toLocaleString();\n } catch {\n return dateString;\n }\n }\n\n private async storeData(data: unknown, schema: string): Promise<string | undefined> {\n try {\n const storageAdapters = this.processor.listStorageAdapters();\n if (storageAdapters.length > 0) {\n const storage = this.processor.getStorage(storageAdapters[0]);\n if (storage) {\n const result = await storage.create(data, schema);\n defaultLogger.info('Data stored successfully', { schema, recordId: result?.id });\n return result?.id;\n }\n }\n } catch (error) {\n defaultLogger.error('Failed to store data', { \n error: (error as Error).message, \n schema \n });\n // Don't throw - storage failure shouldn't break the command\n }\n return undefined;\n }\n\n private getAirtableRecordLink(tableName: string, recordId: string): string | null {\n try {\n // Map table name to schema name\n const schemaMap: Record<string, string> = {\n 'Events': 'event',\n 'Updates': 'update',\n 'Links': 'link'\n };\n \n const schema = schemaMap[tableName];\n if (!schema) {\n defaultLogger.warn('Unknown table name for Airtable link', { tableName });\n return null;\n }\n\n // Get Airtable base ID from storage adapter\n const storageAdapters = this.processor.listStorageAdapters();\n if (storageAdapters.length > 0) {\n const storage = this.processor.getStorage(storageAdapters[0]);\n if (storage && 'getBaseId' in storage && 'getTableId' in storage && 'getViewId' in storage) {\n const baseId = (storage as any).getBaseId();\n const tableId = (storage as any).getTableId(schema);\n const viewId = (storage as any).getViewId(schema);\n return `https://airtable.com/${baseId}/${tableId}/${viewId}/${recordId}?blocks=hide`;\n }\n }\n } catch (error) {\n defaultLogger.warn('Could not generate Airtable link', { error: (error as Error).message });\n }\n return null;\n }\n\n // Public methods\n async start(): Promise<void> {\n defaultLogger.info('Starting Telegram bot...');\n \n try {\n await this.bot.launch();\n defaultLogger.info('Telegram bot started successfully');\n \n // Graceful shutdown\n process.once('SIGINT', () => this.stop());\n process.once('SIGTERM', () => this.stop());\n \n } catch (error) {\n defaultLogger.error('Failed to start Telegram bot', { \n error: (error as Error).message \n });\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n defaultLogger.info('Stopping Telegram bot...');\n this.bot.stop();\n defaultLogger.info('Telegram bot stopped');\n }\n\n // Add custom command handler\n addCommand(command: string, handler: (ctx: Context) => Promise<void>): void {\n this.bot.command(command, handler);\n }\n\n // Get underlying bot instance for advanced usage\n getBot(): Telegraf {\n return this.bot;\n }\n\n // Get processor instance\n getProcessor(): ContentProcessor {\n return this.processor;\n }\n}"],"mappings":"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","names":[]}