Ctrl K
ComunidadGuías…

config.yaml.example

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Telegram channels/chats to monitor
channels:
  - id: "@channelname"
    name: "Example Channel"
    # group: Jobs              # optional — bind to a digest_groups entry (or "Other")
    # prompt_extra: ""         # optional — append extra instructions to this channel's AI prompt
    # lookback_hours: null     # optional — override global lookback_hours for this channel
    # filters: null            # optional — null=use global filters, []=no filters, list=override
  # Add your channels here
  # Format for public channels: "@channelname" (string with quotes)
  # Format for private channels/groups: -1001234567890 (integer, NO quotes!)
  #
  # IMPORTANT: Get the correct channel ID using @RawDataBot
  # - Forward a message from the channel to @RawDataBot
  # - Copy the complete chat ID (should start with -100)
  #
  # ✅ Correct:   id: -1001234567890  (integer with -100 prefix, no quotes)
  # ❌ Wrong:     id: "-1001234567890" (has quotes)
  # ❌ Wrong:     id: -1234567890     (missing -100 prefix)

# Application settings
settings:
  # Scheduling
  schedule_time: "08:00"   # UTC time for daily digest
  timezone: "UTC"
  lookback_hours: 24       # Message collection window

  # AI Provider: "openai", "ollama", or "anthropic"
  # Required env vars per provider:
  #   openai    -> OPENAI_API_KEY in .env
  #   anthropic -> ANTHROPIC_API_KEY in .env
  #   ollama    -> no API key needed
  ai_provider: "openai"

  # AI Model (provider-specific)
  # OpenAI: "gpt-6-luna", "gpt-6-sol", "gpt-6-astra", "gpt-5-nano", "gpt-4o-mini", etc.
  # Ollama: "llama3", "mistral", "gemma2", etc.
  # Anthropic: "claude-sonnet-4-5-20250929", etc.
  ai_model: "gpt-5-nano"

  # Legacy OpenAI settings (used as fallback if ai_model not set)
  openai_model: "gpt-5-nano"
  openai_temperature: 1.0
  max_tokens_per_summary: 1500

  # Ollama settings (only used when ai_provider is "ollama")
  ollama_base_url: "http://localhost:11434"

  # Digest mode: "channel" (default) groups by channel, "digest" groups by topic
  digest_mode: "channel"
  # Deduplicate cross-channel topics: when true, the AI keeps only the most informative
  # bullet point when multiple channels cover the same event (sources are merged).
  # Only effective in digest_mode: "digest".
  # dedup_topics: false
  # Topic groups for digest mode (only used when digest_mode is "digest")
  # An implicit "Other" group catches anything that doesn't match defined groups.
  # digest_groups:
  #   - name: "Events"
  #     description: "Conferences, meetups, releases, launches, announcements"
  #     prompt_extra: ""       # optional — append extra instructions to all channels in this group
  #   - name: "News"
  #     description: "Politics, economy, world affairs, breaking news"
  #   - name: "Sport"
  #     description: "Sports results, transfers, tournaments, matches"

  # Filter chain — drop messages before they reach storage and the AI
  # Runs after collection; filtered messages are never stored or summarized.
  # Built-in filters: KeywordFilter, RegexFilter, MinLengthFilter
  # filters:
  #   - class_path: src.extensions.filters.KeywordFilter
  #     config:
  #       include: ["job", "hiring", "remote"]
  #       exclude: ["nsfw"]
  #   - class_path: src.extensions.filters.MinLengthFilter
  #     config:
  #       min_chars: 30

  # Output
  output_language: "Russian"  # Language for AI summaries (e.g., "English", "Russian", "Spanish")
  use_emojis: true
  include_statistics: true

  # Telegram Bot
  target_user_id: 0  # Your Telegram user ID (`main.py init` fills it; or get from @userinfobot)
  auto_cleanup_old_digests: true  # Automatically delete previous digest messages

  # Safety limits
  max_messages_per_channel: 500
  max_prompt_chars: 8000  # Max characters of message content fed to AI per channel.
                          # Keeps the most recent messages that fit. Increase for models with
                          # large context windows; decrease if you hit "empty content + finish_reason=length".
                          #
                          # How to calculate:
                          #   1. Find your model's context window (total tokens for input + output):
                          #      - OpenAI:    https://platform.openai.com/docs/models
                          #      - Anthropic: https://docs.anthropic.com/en/docs/about-claude/models
                          #      - Ollama:    check model card on https://ollama.com/library
                          #   2. Subtract max output tokens (e.g. max_tokens_per_summary * 2 as buffer)
                          #   3. Subtract ~2000 tokens for system prompt and formatting
                          #   4. Multiply remaining tokens by chars-per-token ratio:
                          #      - English text:          ~4 chars/token
                          #      - Russian/Cyrillic text: ~2-3 chars/token
                          #      - Mixed/CJK text:       ~1.5-2 chars/token
                          #
                          # Example for gpt-4o-mini (128K context, 16K max output):
                          #   (128000 - 16000 - 2000) * 2.5 = 275,000 chars (aggressive)
                          #   Safe recommendation: 50000 (conservative for Russian content)
                          #
                          # Example for claude-sonnet (200K context, 8K max output):
                          #   (200000 - 8000 - 2000) * 2.5 = 475,000 chars (aggressive)
                          #   Safe recommendation: 100000
                          #
                          # Example for ollama llama3-8b (8K context, 2K max output):
                          #   (8000 - 2000 - 2000) * 2.5 = 10,000 chars
                          #   Safe recommendation: 8000
  api_timeout: 30  # Ollama may need 120-300s for local models (enforced minimum: 120s)

# Prompt customization — top-level block (sibling of settings:, not nested inside it)
# base_template: path to the system prompt template file ({language} is substituted at runtime)
# composer: dotted path to a custom PromptComposer class; empty = built-in DefaultComposer
# prompts:
#   base_template: src/prompts/base_summary.txt
#   composer: ""

# Storage — persist raw messages for history / external LLM workflows
# Note: storage is append-only; overlapping lookback windows produce duplicate rows.
# storage:
#   enabled: false
#   backend: sqlite          # "sqlite" (default, no extra setup) or "postgres"
#   path: data/messages.db   # sqlite only — relative to project root; mount as volume in Docker
#   url: ""                  # postgres: postgresql://user:pass@host:5432/db

# MCP server — expose digests to MCP clients (Claude Code, etc.) over HTTP
# Runs inside the Telebrief process; tools: get_digest(hours), get_last_digest()
# Connect with: claude mcp add --transport http telebrief http://127.0.0.1:8765/mcp
# WARNING: there is no authentication. Keep host on loopback, or firewall the port.
# In Docker, publish it as "127.0.0.1:8765:8765" rather than binding 0.0.0.0 openly.
# mcp:
#   enabled: false
#   host: "127.0.0.1"
#   port: 8765
#   path: "/mcp"