# Классификатор: словари ключевых слов по направлениям (MUST: словарный фильтр первым). # Направления расширяемы; для прототипа — linux (основное) + общие. # Канонический список направлений (AGENT.MD, веб-форма fan-out): DIRECTIONS_CANON = ["linux", "tech", "politics", "games", "electronics", "llm"] DIRECTIONS = { "linux": { "keywords": [ "linux", "kernel", "gnome", "kde", "distro", "distribution", "ubuntu", "fedora", "debian", "arch", "manjaro", "mint", "opensuse", "xfce", "wayland", "xorg", "systemd", "apt", "dnf", "pacman", "aur", "snap", "flatpak", "bash", "zsh", "terminal", "shell", "foss", "open source", "opensource", "поверх", "ядро", "дистрибутив", "пакетный менеджер", "реестр пакетов", "libreoffice", "gimp", "вокал", "linux-", "tux", "posix", "unix", "gnu", "kde plasma", "gtk", "qt", "docker", "podman", "k8s", "kubernetes", "контейнер", "образ", "контейнеризация", "self-host", "selfhost", "homelab", "сервер", "vps", "devops", "инфраструктура", "nginx", "postgres", "sqlite", "redis", "grafana", "prometheus", "ansible", "terraform", "caddy", "docker-compose", "compose", "proxy", "vpn", "wireguard", "ssh", "sftp", "tmux", "vim", "neovim", "emacs", "git", "github", "gitlab", "open source", "клонирование", "репозиторий", "пакет", "сборка", "компиляция", "cli", "консоль", "командная строка", "python", "c++", "rust", "go", "golang", "golang", "programming", "программирование", "разработка", "код", "скрипт", "автоматизация", "юникс", "линукс", "пентинг", "security", "безопасность", "шифрование", "gnupg", "firewall", "iptables", "nftables", "selinux", "apparmor", "btrfs", "ext4", "zfs", "файловая система", "lvm", "raid", "ssd", "nvme", "железо", "драйвер", "фирмware", "прошивка", "bios", "uefi", "grub", "безголовый", "headless", "микросервис", "api", "rest", "http", "tcp", "udp", ], # дополнительные точные фразы (более сильные) "phrases": ["linux", "ubuntu", "debian", "arch linux", "fedora", "kernel", "gnome", "kde"], }, "tech": { "keywords": [ # dev (бывший отдельный; разработка/программирование — tech) "разработка", "программирование", "код", "python", "golang", "golang", "rust", "javascript", "typescript", "node", "react", "vue", "next.js", "docker", "kubernetes", "api", "backend", "frontend", "фреймворк", "алгоритм", "open source", "github", "gitlab", "ci/cd", "тестирование", "деплой", "микросервисы", "база данных", "sql", "nosql", "инженер", "разработчик", "программист", "компилятор", "интерпретатор", "ide", "дебаггер", "рефакторинг", "собеседование", "технологии", # tech (бывший) "технологии", "гаджет", "смартфон", "процессор", "чип", "android", "iphone", "apple", "google", "microsoft", "windows", "железо", "компьютер", "ноутбук", "сервер", "storage", "хранилище", "облако", "cloud", "интернет вещей", "iot", "робот", "робототехника", "экран", "дисплей", "батарея", "зарядка", "usb-c", "хакер", "уязвимость", "эксплойт", "zero-day", "шифрование", "приватность", ], "phrases": ["смартфон", "гаджет", "чип", "apple", "технологии", "программирование", "разработка", "software", "developer", "code"], }, "politics": { "keywords": [ "политика", "президент", "выборы", "закон", "законопроект", "госдума", "кремль", "дума", "правительство", "министр", "санкции", "война", "мир", "конфликт", "армия", "нато", "украина", "россия", "сша", "китай", "евросоюз", "телеграм-канал", "депутат", "партия", "референдум", "голосование", "политик", "геополитика", "международный", "амбассадор", "посол", "договор", "переговоры", ], "phrases": ["политика", "выборы", "президент", "госдума", "санкции", "война"], }, "games": { "keywords": [ "игра", "игры", "гейминг", "gaming", "steam", "playstation", "xbox", "nintendo", "геймпад", "игровая консоль", "видеоигра", "мморпг", "шутер", "стратегия", "симулятор", "инди-игра", "киберспорт", "esports", "виртуальная реальность", "vr", "игровой движок", "unity", "unreal", "геймер", ], "phrases": ["игра", "гейминг", "steam", "gaming"], }, "electronics": { "keywords": [ "электроника", "микроконтроллер", "arduino", "raspberry", "esp32", "esp8266", "пайка", "схема", "плата", "микросхема", "транзистор", "резистор", "конденсатор", "осциллограф", "мультиметр", "радио", "антенна", "sdr", "fpga", "промышленность", "электронный", "компонент", "датчик", "силовой", "реле", ], "phrases": ["arduino", "raspberry", "fpga", "микроконтроллер"], }, "llm": { "keywords": [ "ии", "ai", "llm", "gpt", "нейросеть", "нейронная сеть", "deep learning", "машинное обучение", "ml", "модель", "обучение модели", "инференс", "файнтюнинг", "fine-tuning", "rlhf", "агент", "агенты", "генеративный", "стабильная диффузия", "stable diffusion", "midjourney", "чат-бот", "chatbot", "ассистент", "токен", "трансформер", "embedding", "векторная база", "rag", "pipeline", "инференс", "openai", "антропик", "claude", "gemini", "olama", "qwen", ], "phrases": ["нейросеть", "llm", "чат-бот", "openai", "claude"], }, } import re # Направление по умолчанию, если ничего не подошло DEFAULT_DIRECTION = "linux" # прототип: все посты про linux окружение def find_directions_all(text: str) -> list[str]: """Возвращает ВСЕ направления, которым соответствует текст (для мультинаправлений/fan-out).""" text_low = (text or "").lower() hits = set() for direction, cfg in DIRECTIONS.items(): # точные фразы if any(p.lower() in text_low for p in cfg.get("phrases", [])): hits.add(direction) continue # ключевые слова (по слову, re.search с границами) for kw in cfg.get("keywords", []): kw_low = kw.lower() if re.search(rf"\b{re.escape(kw_low)}\b", text_low): hits.add(direction) break return list(hits) def find_direction(text: str) -> str | None: """Возвращает направление, если текст совпал со словарём (иначе None).""" dirs = find_directions_all(text) if dirs: return dirs[0] return None