### Ruby: Example of a Simple Inline Keyboard Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Provides a practical example of generating a simple inline keyboard with two rows of buttons using the `inline_keyboard`, `keyboard_row`, and `callback_button` helpers. ```ruby def start_keyboard inline_keyboard( keyboard_row( callback_button('Начать', 'start_onboarding:'), callback_button('Подробнее', 'more_info:') ), keyboard_row( callback_button('⚙️ Настройки', 'settings:') ) ) end ``` -------------------------------- ### Ruby Example: Creating and Responding with a Telegram Inline Keyboard Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Provides a complete example of generating an inline keyboard using `Telegram::KeyboardHelpers` and responding to a user with this keyboard. It demonstrates defining a keyboard layout and using `respond_with` to send the message and keyboard. ```ruby def welcome_keyboard inline_keyboard( keyboard_row( callback_button('Начать', 'start:'), callback_button('Помощь', 'help:') ), keyboard_row( url_button('Наш сайт', 'https://example.com') ) ) end respond_with :message, text: 'Добро пожаловать!', reply_markup: welcome_keyboard ``` -------------------------------- ### Example Usage of AI::SessionManager in Ruby Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md This snippet demonstrates how to instantiate and use the `AI::SessionManager` class for AI operations. It shows examples of using `with_schema` for structured output and `with_tools` for AI functionalities that require external tools. ```ruby # Использование session_manager = AI::SessionManager.new(user, :classification) # С Structured Output result = session_manager.with_schema(Schemas::PostClassificationSchema) do |chat, session| chat.ask("Классифицируй этот пост: #{post.text}") end # С Tools result = session_manager.with_tools([Tools::ClassifyPostTool]) do |chat, session| chat.ask("Проанализируй этот пост: #{post.text}") end ``` -------------------------------- ### AI Classifier Service Initialization and Classification Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md Initializes the AI Classifier with a user and session manager. The `classify` method uses Rails caching to store classification results for a post, while `classify_with_context` enriches the classification with user-specific few-shot examples before saving. ```ruby module Content class AIClassifier attr_reader :user, :session_manager def initialize(user) @user = user @session_manager = AI::SessionManager.new(user, :classification) end def classify(post) # Использовать кеширование cache_key = "classification/#{post.id}/#{user.id}" dependencies = [user, post] Rails.cache.fetch(cache_key, expires_in: 24.hours) do perform_classification(post) end end def classify_with_context(post) result = @session_manager.with_schema(Schemas::PostClassificationSchema) do |chat, session| classify_request(chat, post) end save_classification(post, result) result end private def perform_classification(post) start_time = Time.current result = @session_manager.with_schema(Schemas::PostClassificationSchema) do |chat, session| # Построить контекст с few-shot примерами context = build_classification_context(post) response = chat.ask( "#{context}\n\nТеперь классифицируй этот пост:\n\n#{post.text}" ) response end # Логировать метрики log_classification_metrics(post, result, Time.current - start_time) result end def build_classification_context(post) # Добавить few-shot примеры из фидбека few_shot = Personalization::FewShotBuilder.new(@user) examples = few_shot.build_examples return "" if examples.empty? <<~CONTEXT Вот несколько примеров того, как пользователь оценивал похожие посты: #{format_few_shot_examples(examples)} Используй эти примеры для понимания предпочтений пользователя. CONTEXT end def format_few_shot_examples(examples) examples.map.with_index do |(user_msg, assistant_msg), i| <<~EXAMPLE Пример #{i + 1}: #{user_msg[:content]} Оценка: #{JSON.parse(assistant_msg[:content])['importance_score']}/100 Реакция пользователя: #{JSON.parse(assistant_msg[:content])['user_liked'] ? '👍' : '👎'} EXAMPLE end.join("\n") end def save_classification(post, result) post.update!( classification_data: { importance_score: result.importance_score, is_ad: result.is_ad, is_fluff: result.is_fluff, duplicate_check: result.duplicate_check, confidence: result.confidence }, topics: result.topics, classification_reasoning: result.reasoning, classified_by_session_id: @session_manager.session.id ) # Создать персональную классификацию PostClassification.create!( post: post, user: @user, chat: @session_manager.session, importance_score: result.importance_score, is_relevant: result.importance_score >= relevance_threshold, reasoning: result.reasoning, confidence: result.confidence ) end def relevance_threshold Personalization::ThresholdAdjuster.new(@user).adjusted_threshold end def log_classification_metrics(post, result, duration) Rails.logger.info({ event: 'ai_classification', user_id: @user.id, post_id: post.id, importance_score: result.importance_score, is_ad: result.is_ad, confidence: result.confidence, duration_seconds: duration.round(2), session_id: @session_manager.session.id }.to_json) end end end ``` -------------------------------- ### RSpec Testing Telegram Bot Controllers with Commands and Messages Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Demonstrates RSpec tests for a `TelegramWebhookController`. It covers dispatching commands like 'start', handling regular messages, and processing callback queries, using `send_telegram_message` and `answer_callback_query` matchers. ```ruby require 'telegram/bot/updates_controller/rspec_helpers' RSpec.describe TelegramWebhookController, type: :telegram_bot_controller do describe '#start!' do subject { -> { dispatch_command :start } } it 'responds with greeting' do expect { subject.call }.to send_telegram_message( bot, text: /Привет/ ) end end describe '#message' do let(:message_text) { 'Hello' } it 'echoes the message' do expect { dispatch_message message_text }.to send_telegram_message( bot, text: "Вы написали: #{message_text}" ) end end describe '#callback_query' do it 'handles button click' do expect { dispatch_callback_query 'button_clicked' } .to answer_callback_query('Готово!') end end end ``` -------------------------------- ### Ruby AI Context Builder: Feedback Context Generation Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md Generates contextual information from user feedback for AI prompts. It includes recent feedback examples and analyzes patterns in liked and disliked topics and post importance scores. This context helps the AI understand user preferences better. ```ruby module AI class ContextBuilder # ... other methods private def feedback_context return "" unless @user.feedbacks.any? examples = @user.recent_feedback_summary(limit: 10) patterns = analyze_feedback_patterns <<~CONTEXT ## Последние примеры фидбека пользователя #{format_feedback_examples(examples)} ## Выявленные паттерны предпочтений #{patterns} CONTEXT end def format_feedback_examples(examples) examples.map do |ex| sentiment = ex[:liked] ? "👍 Понравился" : "👎 Не понравился" topics = ex[:topics].any? ? ex[:topics].join(', ') : "без тем" "- #{sentiment} | Важность: #{ex[:post_importance]}/100 | Темы: #{topics}" end.join("\n") end def analyze_feedback_patterns # Анализ предпочтений по темам liked_topics = @user.feedbacks.liked .joins(:post) .where.not("posts.topics": []) .pluck('posts.topics') .flatten .tally .sort_by { |_, count| -count } .first(5) disliked_topics = @user.feedbacks.disliked .joins(:post) .where.not("posts.topics": []) .pluck('posts.topics') .flatten .tally .sort_by { |_, count| -count } .first(3) patterns = [] if liked_topics.any? top_likes = liked_topics.map { |t, c| "#{t} (#{c})" }.join(', ') patterns << "- Интересующие темы: #{top_likes}" end if disliked_topics.any? top_dislikes = disliked_topics.map { |t, c| "#{t} (#{c})" }.join(', ') patterns << "- Неинтересующие темы: #{top_dislikes}" end # Анализ предпочитаемых оценок avg_liked_score = @user.feedbacks.liked .joins(:post) .average('posts.importance_score') .to_f.round if avg_liked_score > 0 patterns << "- Средняя оценка понравившихся постов: #{avg_liked_score}/100" end patterns.join("\n") end end end ``` -------------------------------- ### Ruby AI Context Builder: System Prompt Generation Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md Generates a system prompt for an AI based on the session type and user attributes. It includes user-specific details like filter strictness, content format, subscription count, timezone, and feedback patterns. The prompt guides the AI's task, such as content classification or summarization. ```ruby module AI class ContextBuilder MAX_HISTORY_MESSAGES = 20 MAX_FEW_SHOT_EXAMPLES = 10 attr_reader :session, :user def initialize(session, user) @session = session @user = user end def system_prompt case @session.session_type.to_sym when :classification classification_system_prompt when :summarization summarization_system_prompt when :personalization personalization_system_prompt when :digest_generation digest_generation_system_prompt end end private def classification_system_prompt <<~PROMPT Ты — система классификации контента для персонального Telegram бота "Без шелухи". ## Информация о пользователе - Уровень строгости фильтрации: #{@user.filter_strictness} - Предпочитаемый формат контента: #{@user.content_format} - Количество подписок: #{@user.subscriptions.count} - Часовой пояс: #{@user.timezone || 'UTC'} #{feedback_context if @user.feedbacks.any?} ## Твоя задача Оценить важность поста от 0 до 100, определить: - Является ли он рекламой или шелухой - Какие темы затрагивает - Насколько соответствует интересам данного пользователя ## Критерии оценки - **90-100**: Критически важная информация, прорывы, важные новости - **70-89**: Очень интересный и полезный контент - **50-69**: Умеренно интересный контент - **30-49**: Малоинтересный контент - **0-29**: Шелуха, реклама, спам Используй примеры из истории фидбека, чтобы понять предпочтения пользователя. PROMPT end def summarization_system_prompt <<~PROMPT Ты — эксперт по созданию кратких и информативных саммари. Твоя задача — создавать краткие (2-3 предложения) саммари постов, сохраняя самую важную информацию и основную идею. Формат: #{@user.content_format} PROMPT end def personalization_system_prompt <<~PROMPT Ты — система персонализации, анализирующая предпочтения пользователя. Анализируй фидбек (лайки/дизлайки) и определяй паттерны: - Какие темы интересуют пользователя - Какой стиль контента предпочитает - Какую глубину и детальность ожидает Используй эти знания для улучшения классификации в будущем. PROMPT end def digest_generation_system_prompt <<~PROMPT Ты — помощник по созданию персонализированных дайджестов. Создавай дайджесты в формате "#{@user.content_format}": - Группируй похожие посты - Выделяй самое важное - Сохраняй структуру и читаемость PROMPT end end end ``` -------------------------------- ### Ruby AI Context Builder: Relevant History Retrieval Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md Retrieves and limits the relevant message history for AI context. It combines important examples, recent interactions, and few-shot examples from feedback, ensuring uniqueness and sorting by creation time. The history is then truncated to a maximum of MAX_HISTORY_MESSAGES. ```ruby module AI class ContextBuilder MAX_HISTORY_MESSAGES = 20 MAX_FEW_SHOT_EXAMPLES = 10 attr_reader :session, :user def initialize(session, user) @session = session @user = user end def relevant_history # Комбинировать разные типы релевантных сообщений messages = [ important_examples, recent_interactions, few_shot_from_feedback ].flatten.uniq(&:id).sort_by(&:created_at) # Ограничить общее количество messages.last(MAX_HISTORY_MESSAGES) end # ... other methods end end ``` -------------------------------- ### Manage AI Session Context in Ruby Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md The `with_context` method executes a block of code within the context of an AI session. It builds the chat with relevant context and updates session metrics after execution. It's designed to manage the lifecycle of an AI chat interaction, ensuring proper setup and cleanup. ```ruby module AI class SessionManager attr_reader :user, :session def initialize(user, session_type) @user = user @session = find_or_create_session(session_type) end # Выполнить операцию с AI в контексте сессии def with_context(&block) chat = build_chat_with_context result = yield chat, @session # Обновить метрики сессии update_session_metrics cleanup_if_needed result end private def find_or_create_session(type) @user.chat_for(type) end def build_chat_with_context context_builder = AI::ContextBuilder.new(@session, @user) # Использовать managed context для оптимизации токенов @session.chat_instance.tap do |chat| chat.system_message = context_builder.system_prompt # Ограничить историю релевантными сообщениями chat.history = context_builder.relevant_history end end def update_session_metrics @session.touch(:last_activity_at) @session.increment!(:messages_count) end def cleanup_if_needed # Архивировать старые сообщения если сессия слишком большая if @session.messages_count > 100 Rails.logger.info "Compacting AI session #{@session.id} (#{@session.messages_count} messages)" @session.compact_history end end end end ``` -------------------------------- ### RSpec Configuration for Telegram Bots in Rails Test Environment Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Configures the Rails test environment for RSpec testing of Telegram bots. It ensures Telegram bots are reset before tests run, crucial for isolated testing. This setup should be performed before route definitions. ```ruby # Важно: выполнить ДО определения маршрутов! Telegram.reset_bots Telegram::Bot::ClientStub.stub_all! ``` -------------------------------- ### RSpec Matchers for Verifying Telegram Message Sending Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Provides examples of RSpec matchers for asserting that specific Telegram messages are sent. Covers basic message sending, messages with specific text content (exact match and regex), and messages with reply keyboards. ```ruby # Проверить, что сообщение отправлено expect { dispatch_command :start }.to send_telegram_message(bot) # С конкретным текстом expect { dispatch_command :start }.to send_telegram_message( bot, text: 'Привет!' ) # С regexp expect { dispatch_command :start }.to send_telegram_message( bot, text: /Привет/ ) # С клавиатурой expect { dispatch_command :menu }.to send_telegram_message( bot, text: 'Меню', reply_markup: kind_of(Telegram::Bot::Types::InlineKeyboardMarkup) ) ``` -------------------------------- ### Ruby: Old vs New Inline Keyboard Creation Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Demonstrates the verbose traditional method of creating inline keyboards versus the cleaner approach using Telegram::KeyboardHelpers. This helps in understanding the problem and the benefits of the concern. ```ruby # Старый способ kb = [ [ Telegram::Bot::Types::InlineKeyboardButton.new( text: 'Настройки', callback_data: 'settings:' ), Telegram::Bot::Types::InlineKeyboardButton.new( text: 'Помощь', callback_data: 'help:' ) ], [ Telegram::Bot::Types::InlineKeyboardButton.new( text: 'Назад', callback_data: 'main:' ) ] ] Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: kb) ``` ```ruby # Новый способ inline_keyboard( keyboard_row( callback_button('Настройки', 'settings:'), callback_button('Помощь', 'help:') ), keyboard_row( callback_button('Назад', 'main:') ) ) ``` -------------------------------- ### Ruby: Assembling Inline Keyboards with inline_keyboard Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Demonstrates the `inline_keyboard` helper method, which takes one or more rows of buttons (created with `keyboard_row`) and assembles them into a complete inline keyboard markup. ```ruby inline_keyboard( keyboard_row(button1, button2), keyboard_row(button3), keyboard_row(button4, button5, button6) ) ``` -------------------------------- ### Ruby: Universal Button Creation with button Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Explains the versatile `button` helper method, which can create callback buttons, URL buttons, or buttons for inline queries. It allows for additional Telegram API options to be passed. ```ruby # Callback кнопка button('Настройки', 'settings:') # URL кнопка button('Google', nil, url: 'https://google.com') # Inline query кнопка button('Поиск', nil, switch_inline_query: 'query') # С дополнительными параметрами button('Текст', 'data', **{parse_mode: 'Markdown'}) ``` -------------------------------- ### Ruby: Dynamic Keyboard Generation for Subscriptions Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Illustrates how to create an inline keyboard with dynamically generated buttons based on a collection of subscriptions. It uses `map` to create buttons for each subscription and handles an empty state. ```ruby def subscriptions_keyboard(subscriptions) return nil if subscriptions.empty? keyboard = subscriptions.map do |subscription| keyboard_row( callback_button('⬆️', "priority_up:#{subscription.channel_id}"), callback_button('⬇️', "priority_down:#{subscription.channel_id}"), callback_button('❌', "remove_channel:#{subscription.channel_id}") ) end inline_keyboard(*keyboard) end ``` -------------------------------- ### Ruby: Creating URL Buttons with url_button Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Demonstrates the `url_button` helper method for creating inline keyboard buttons that open a specified URL. It takes the button text and the URL as parameters. ```ruby url_button('Google', 'https://google.com') url_button('Перейти', post.link) ``` -------------------------------- ### Execute AI Operations with Tools in Ruby Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md The `with_tools` method allows AI operations to utilize specific tools. It uses the `with_context` method and configures the chat with a provided array of tools before yielding to a block. This is essential for enabling the AI to perform actions or access external information. ```ruby # Выполнить операцию с tools def with_tools(tools_array, &block) with_context do |chat, session| chat_with_tools = RubyLLM.chat( tools: tools_array, system: chat.system_message ) yield chat_with_tools, session end end ``` -------------------------------- ### Execute AI Operations with Schema in Ruby Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/implementation-examples.md The `with_schema` method enables AI operations that require structured output. It leverages the `with_context` method and enhances the chat instance with a specified schema class before yielding control to a block. This is useful for ensuring AI responses conform to a predefined structure. ```ruby # Выполнить операцию с structured output def with_schema(schema_class, &block) with_context do |chat, session| chat_with_schema = chat.with_schema(schema_class) yield chat_with_schema, session end end ``` -------------------------------- ### Ruby: Mixed Button Types in Complex Keyboard Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Demonstrates the creation of an inline keyboard that includes different types of buttons: callback buttons, URL buttons, and inline query buttons, showcasing the flexibility of the `button` helper. ```ruby def complex_keyboard inline_keyboard( keyboard_row( callback_button('Действие 1', 'action1:'), url_button('Внешний сайт', 'https://example.com') ), keyboard_row( button('Поиск', nil, switch_inline_query: 'search:') ) ) end ``` -------------------------------- ### Ruby Telegram Keyboard Helper: Button Creation Methods Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Details helper methods for creating individual buttons within Telegram inline keyboards using `Telegram::KeyboardHelpers`. It includes `button` for general-purpose buttons, `callback_button` for buttons triggering callbacks, and `url_button` for linking to external URLs. ```ruby button('Текст', 'data') button('Текст', nil, url: 'https://example.com') button('Текст', nil, switch_inline_query: 'query') callback_button('Настройки', 'settings:') callback_button('Удалить', "delete:#{item.id}") url_button('Google', 'https://google.com') url_button('Открыть', item.link) ``` -------------------------------- ### Ruby Telegram Keyboard Helper: InlineKeyboardMarkup Assembly Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Explains how to assemble a complete `InlineKeyboardMarkup` using `Telegram::KeyboardHelpers`. It utilizes `inline_keyboard` to group rows of buttons, which are themselves created using `keyboard_row`. ```ruby inline_keyboard( keyboard_row(button1, button2), keyboard_row(button3) ) ``` -------------------------------- ### Ruby: Creating Callback Buttons with callback_button Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Illustrates the usage of the `callback_button` helper method to create inline keyboard buttons that trigger a callback when pressed. It accepts text and callback data as arguments. ```ruby callback_button('Настройки', 'settings:') callback_button('Удалить', "delete:#{item.id}") ``` -------------------------------- ### Telegram::Bot::ClientStub API for Mocking Bot Requests Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Details the API of `Telegram::Bot::ClientStub` for mocking and inspecting bot requests during testing. It shows how to retrieve all requests, access the last request, and clear the request log. ```ruby # Проверить все запросы Telegram.bot.requests # Последний запрос Telegram.bot.requests.last # Очистить запросы Telegram.bot.reset ``` -------------------------------- ### Ruby Telegram Keyboard Helper for Inline Keyboards Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Introduces `Telegram::KeyboardHelpers`, a concern for simplifying the creation of Telegram inline keyboards within controllers. It provides methods for generating buttons, rows, and full keyboard layouts. ```ruby class MyController < Telegram::Bot::UpdatesController include Telegram::KeyboardHelpers end ``` -------------------------------- ### Ruby: Creating a Row of Buttons with keyboard_row Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Shows how to group multiple buttons into a single row using the `keyboard_row` helper method. This is a building block for creating the complete inline keyboard. ```ruby keyboard_row( callback_button('Да', 'yes'), callback_button('Нет', 'no') ) ``` -------------------------------- ### Mermaid: System Context Diagram for NoFluff Bot Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/c4-model.md Диаграмма контекста системы, иллюстрирующая взаимодействие NoFluff Bot с пользователями и внешними системами, такими как Telegram Bot API и AI/LLM Service. ```mermaid C4Context title System Context diagram для NoFluff Bot Person(user, "Пользователь Telegram", "Хочет получать важный контент из каналов без шелухи") System(nofluff, "NoFluff Bot System", "Фильтрует контент из Telegram каналов, обнаруживает дубликаты, формирует персонализированные дайджесты") System_Ext(telegram, "Telegram Bot API", "API для взаимодействия с Telegram") System_Ext(telegram_channels, "Telegram Channels", "Публичные Telegram каналы, за которыми следит бот") System_Ext(ai_service, "AI/LLM Service", "Сервис для классификации важности, генерации саммари, определения дубликатов") Rel(user, nofluff, "Управляет настройками, получает дайджесты", "Telegram") Rel(nofluff, telegram, "Отправляет/получает сообщения", "HTTPS/Webhook") Rel(nofluff, telegram_channels, "Мониторит новые посты", "Telegram API") Rel(nofluff, ai_service, "Классифицирует контент, генерирует саммари", "HTTPS/API") ``` -------------------------------- ### Ruby: Conditional Buttons in Delivery Frequency Keyboard Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Shows how to create an inline keyboard with conditional logic for button text and callback data. This allows the UI to reflect the current state, such as the user's delivery frequency setting. ```ruby def delivery_frequency_keyboard inline_keyboard( keyboard_row( callback_button( 'Реальное время', current_user.delivery_frequency_real_time? ? 'settings:' : 'set_delivery_frequency:real_time' ), callback_button( '3 раза в день', current_user.delivery_frequency_three_times_daily? ? 'settings:' : 'set_delivery_frequency:three_times_daily' ) ), keyboard_row( callback_button('← Назад', 'settings:') ) ) end ``` -------------------------------- ### Mermaid: Container Diagram for NoFluff Bot Source: https://github.com/dapi/no_fluff/blob/main/docs/Architecture/c4-model.md Диаграмма контейнеров системы NoFluff Bot, показывающая основные компоненты, такие как Rails API Application, Background Workers, PostgreSQL, Cache и Job Queue, а также их взаимодействие. ```mermaid C4Container title Container diagram для NoFluff Bot Person(user, "Пользователь", "Пользователь Telegram") System_Ext(telegram, "Telegram Bot API") System_Ext(ai, "AI/LLM Service") Container(rails_app, "Rails API Application", "Ruby on Rails 8", "Обрабатывает команды пользователей, управляет бизнес-логикой") Container(bot_workers, "Background Workers", "Solid Queue", "Асинхронная обработка: мониторинг каналов, формирование дайджестов, AI-анализ") ContainerDb(postgres, "Database", "PostgreSQL", "Хранит пользователей, каналы, посты, настройки, статистику") ContainerDb(cache, "Cache", "Solid Cache", "Кеширует результаты AI, дедупликацию, частые запросы") ContainerQueue(queue, "Job Queue", "Solid Queue", "Очередь фоновых задач") Rel(user, telegram, "Отправляет команды", "Telegram") Rel(telegram, rails_app, "Webhook / Long Polling", "HTTPS") Rel(rails_app, postgres, "Читает/пишет данные", "SQL") Rel(rails_app, cache, "Кеширует данные", "Redis Protocol") Rel(rails_app, queue, "Ставит задачи в очередь", "SQL") Rel(bot_workers, queue, "Забирает задачи", "SQL") Rel(bot_workers, postgres, "Обновляет данные", "SQL") Rel(bot_workers, telegram, "Мониторит каналы, отправляет дайджесты", "HTTPS") Rel(bot_workers, ai, "Анализирует контент", "HTTPS") Rel(bot_workers, cache, "Использует кеш", "Redis Protocol") ``` -------------------------------- ### Ruby: Connecting Telegram::KeyboardHelpers Concern Source: https://github.com/dapi/no_fluff/blob/main/docs/Development/keyboard-helpers.md Shows how to include the Telegram::KeyboardHelpers concern within a Telegram bot controller. This makes the helper methods available for creating keyboards. ```ruby class TelegramWebhookController < Telegram::Bot::UpdatesController include Telegram::KeyboardHelpers # ваши методы end ``` -------------------------------- ### RSpec Testing Telegram Bot Session Handling Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Illustrates how to test session handling within a Telegram bot controller using RSpec. It demonstrates setting session variables and asserting that these variables are correctly updated and reflected in bot responses. ```ruby RSpec.describe TelegramWebhookController, type: :telegram_bot_controller do describe 'session handling' do it 'counts visits' do session[:visits] = 5 expect { dispatch_command :start }.to send_telegram_message( bot, text: /6 раз/ ) expect(session[:visits]).to eq(6) end end end ``` -------------------------------- ### Ruby Authorization Middleware for Telegram Bots Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Provides a middleware for handling user authorization in a Telegram bot. It checks if a user is authorized before allowing further processing of updates. Unauthorized users receive a specific message. Dependencies include the bot object for sending messages. ```ruby class AuthorizationMiddleware def initialize(bot) @bot = bot end def call(update) user_id = extract_user_id(update) if authorized?(user_id) yield update else send_unauthorized_message(user_id) end end private def authorized?(user_id) # Проверка авторизации end def extract_user_id(update) update.dig('message', 'from', 'id') || update.dig('callback_query', 'from', 'id') end def send_unauthorized_message(user_id) @bot.send_message( chat_id: user_id, text: 'У вас нет доступа к этому боту' ) end end ``` -------------------------------- ### Ruby Statistics Middleware for Telegram Bots Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Implements a middleware to track user statistics in a Telegram bot. It increments user stats based on the user ID extracted from incoming update objects. This middleware requires the bot object during initialization. ```ruby class StatisticsMiddleware def initialize(bot) @bot = bot end def call(update) user_id = update.dig('message', 'from', 'id') || update.dig('callback_query', 'from', 'id') increment_user_stats(user_id) if user_id yield update end private def increment_user_stats(user_id) # Ваша логика end end ``` -------------------------------- ### RSpec Reset Configuration for Multiple Telegram Bots Source: https://github.com/dapi/no_fluff/blob/main/docs/gems/telegram-bot.md Configures RSpec to reset each Telegram bot after every test, ensuring a clean state for subsequent tests. This is particularly useful when managing multiple bot instances. ```ruby RSpec.configure do |config| # Сброс после каждого теста config.after do Telegram.bot.reset end # Или для нескольких ботов: config.after do Telegram.bots.each_value(&:reset) end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.