fix: PageHead header alignment, analytics proxy, and infra improvements (#64)

🤖 Pull request created from `various-fixes` containing PageHead
breadcrumbs and navigation alignment fixes, Umami analytics proxy, and
infrastructure updates.
This commit is contained in:
deytenit authored and GitHub committed 2026-10-24 16:52:49 +03:00
1 parent ff5a50bad8
commit 9ee672504f
110 files changed
+2649 -1760

No files matched your search

@@ -3,4 +3,4 @@ title: Руководства
weight: 3
---
Пошаговые инструкции и руководства по реализации функций в Quetza.
Пошаговые руководства и инструкции по разработке и настройке возможностей Quetza.
@@ -3,34 +3,34 @@ title: Интеграция разговорного ИИ
weight: 4
---
**Цель:** Интегрировать большие языковые модели (LLM), управляя контекстом и ограничениями тайм-аута Discord.
**Цель:** подключить большие языковые модели (LLM), настроить управление контекстом и уложиться в тайм-ауты Discord.
## 1. Стратегия управления контекстом
Разговоры требуют истории, чтобы быть связными.
Чтобы диалог оставался связным, модели нужна история сообщений:
- **Область видимости (Scoping):** `Map<GuildID, Map<UserID, Message[]>>`
- **Ключ гильдии (Guild Key):** Предотвращает утечки между серверами.
- **Ключ пользователя (User Key):** Предотвращает путаницу между пользователями в публичных каналах.
- **Жизненный цикл:** Реализуйте "скользящее окно" (например, последние 50 сообщений) для предотвращения разрастания контекста.
- **Ключ сервера (Guild Key):** изолирует контекст и защищает от утечек данных между серверами.
- **Ключ пользователя (User Key):** разделяет реплики разных участников в публичных каналах.
- **Жизненный цикл:** настройте «скользящее окно» (например, последние 50 сообщений), чтобы контекст не разрастался.
## 2. Потоковая передача ответов
LLM работают медленно, а Discord требует быстрых ответов (тайм-аут 3 секунды).
LLM генерируют ответ постепенно, а Discord ждёт реакции не дольше 3 секунд.
{{% steps %}}
### Шаг 1: Отложенное взаимодействие (Defer Interaction)
### Шаг 1: Отложенный ответ (Defer Interaction)
Немедленно вызовите `interaction.deferReply()`. Это даст вам 15 минут.
Сразу вызовите `interaction.deferReply()`. Это продлит время ожидания ответа до 15 минут.
### Шаг 2: Вызов LLM
### Шаг 2: Запрос к LLM
Асинхронно вызовите ваш ИИ-сервис.
Асинхронно отправьте запрос к ИИ-сервису.
### Шаг 3: Редактирование ответа
### Шаг 3: Отправка ответа
Когда данные поступят, используйте `interaction.editReply(content)`.
Когда ответ готов, вызовите `interaction.editReply(content)`.
{{% /steps %}}
## 3. Пример реализации
@@ -52,5 +52,5 @@ export async function execute(interaction, controller) {
```
> [!WARNING]
> **Затраты на API:**
> API ИИ часто тарифицируются по токенам. Внедрите строгие лимиты запросов (rate limits) для пользователей в вашем Контроллере, чтобы предотвратить злоупотребления.
> **Расходы на API:**
> Провайдеры ИИ обычно тарифицируют запросы по токенам. Настройте в контроллере строгие лимиты запросов (rate limits) для пользователей, чтобы избежать лишних расходов.
@@ -1,25 +1,25 @@
---
title: Развертывание и эксплуатация
title: Развёртывание и эксплуатация
weight: 2
---
**Цель:** Настроить, развернуть и мониторить экземпляр бота Quetza.
**Цель:** настроить, развернуть и контролировать работу бота Quetza.
## 1. Подготовка окружения
Quetza полагается на переменные окружения для конфигурации. **Никогда** не сохраняйте их в систему контроля версий.
Quetza настраивается через переменные окружения. **Никогда** не сохраняйте их в систему контроля версий.
| Переменная | Описание | Обязательно |
| :--- | :--- | :--- |
| `DISCORD_TOKEN` | Токен бота из Discord Developer Portal | **Да** |
| `CLIENT_ID` | ID приложения для регистрации slash-команд | **Да** |
| `LLAMA_API_KEY` | Требуется при использовании модуля ИИ | Нет |
| `DISCORD_TOKEN` | Токен бота из Discord Developer Portal | **Да** |
| `CLIENT_ID` | Идентификатор приложения для регистрации слэш-команд | **Да** |
| `LLAMA_API_KEY` | Требуется для модуля ИИ | Нет |
## 2. Стратегии развертывания
## 2. Способы развёртывания
{{< tabs >}}
{{< tab name="Docker (Рекомендуется)" >}}
**Docker** обеспечивает стабильное окружение выполнения.
{{< tab name="Docker (рекомендуется)" >}}
**Docker** обеспечивает предсказуемое и изолированное окружение.
1. **Сборка** образа:
@@ -35,8 +35,8 @@ Quetza полагается на переменные окружения для
quetza-bot
```
{{< /tab >}}
{{< tab name="Из исходников (Source)" >}}
Развертывание **из исходников** полезно для разработки.
{{< tab name="Из исходного кода" >}}
Развёртывание **из исходного кода** подходит для разработки и отладки.
1. **Установка** зависимостей:
@@ -57,17 +57,17 @@ Quetza полагается на переменные окружения для
{{< /tab >}}
{{< /tabs >}}
## 3. Операционный мониторинг
## 3. Мониторинг
После запуска используйте следующие механизмы для проверки работоспособности:
После запуска проверьте состояние бота:
- **Логи:** Проверьте стандартный вывод (логи Docker) на наличие ошибок инициализации.
- **Команда `/ping`:** Проверяет задержку сети и отзывчивость API.
- **Команда `/modules`:** Перечисляет все загруженные модули, чтобы подтвердить доступность функций.
- **Логи:** проверьте стандартный вывод (логи Docker) на ошибки инициализации.
- **Команда `/ping`:** измеряет задержку сети и отзывчивость API.
- **Команда `/modules`:** выводит список загруженных модулей, подтверждая доступность функций.
> [!WARNING]
> **Ограничение масштабирования:**
> Quetza следует модели "один экземпляр на один токен". Не запускайте несколько экземпляров с одним и тем же токеном, так как это вызовет конфликты WebSocket.
> Quetza работает по модели «один экземпляр на один токен». Не запускайте несколько копий бота с одним токеном: это вызовет конфликты соединений WebSocket.
---
@@ -1,21 +1,21 @@
---
title: Процесс разработки модуля
title: Разработка модуля
weight: 1
---
**Цель:** Создать новую функцию для бота Quetza путем реализации самодостаточного модуля.
**Цель:** добавить новую возможность в бота Quetza в виде изолированного модуля.
## 1. Фаза концептуализации
## 1. Проектирование модуля
Перед написанием кода определите архитектуру модуля:
Перед написанием кода выберите подходящую структуру модуля:
- **Простая команда:** Требуется только папка `commands/` (например, служебные команды).
- **Реактивная логика:** Нужна папка `events/` для прослушивания жизненного цикла Discord (например, приветственные сообщения).
- **Функция с состоянием:** Требуется **Контроллер** (Controller) для управления состоянием на разных серверах (например, музыкальный плеер).
- **Простая команда:** достаточно каталога `commands/` (например, для служебных команд).
- **Реактивная логика:** нужен каталог `events/` для обработки событий Discord (например, приветственных сообщений).
- **Логика с состоянием:** понадобится контроллер (`Controller`) для управления состоянием между серверами (например, для музыкального плеера).
## 2. Создание структуры
## 2. Структура каталогов
Создайте структуру директорий модуля. Наличие этих файлов запускает автоматическое обнаружение.
Создайте дерево каталогов модуля. Quetza автоматически найдёт и загрузит нужные файлы:
{{< filetree/container >}}
{{< filetree/folder name="src" state="open" >}}
@@ -30,13 +30,13 @@ weight: 1
{{< /filetree/folder >}}
{{< /filetree/container >}}
## 3. Шаги реализации
## 3. Порядок реализации
{{% steps %}}
### Шаг 1: Создание манифеста
### Шаг 1: Манифест модуля
Создайте `module.ts` для объявления модуля.
Создайте `module.ts` с описанием модуля:
```typescript
// src/modules/my-feature/module.ts
@@ -45,9 +45,9 @@ export const description = 'Добавляет крутые возможност
// Опционально: export const controller = new MyFeatureController();
```
### Шаг 2: Реализация команд
### Шаг 2: Команды
Создайте файлы команд в папке `commands/`. Каждый файл экспортирует данные и функцию-исполнитель (executor).
Создайте файлы команд в каталоге `commands/`. Каждый файл экспортирует описание команды и функцию выполнения (`execute`).
```typescript
// src/modules/my-feature/commands/ping.ts
@@ -60,9 +60,9 @@ export async function execute(interaction) {
}
```
### Шаг 3: Реализация событий (Опционально)
### Шаг 3: Обработчики событий (опционально)
Создайте обработчики событий в `events/` для отслеживания состояния Discord.
Создайте обработчики в каталоге `events/`, чтобы реагировать на события Discord:
```typescript
// src/modules/my-feature/events/ready.ts
@@ -76,30 +76,30 @@ export function execute(client) {
}
```
### Шаг 4: Определение контроллера (Опционально)
### Шаг 4: Контроллер (опционально)
Для логики, требующей сохранения состояния, реализуйте контроллер в папке `lib/` и экспортируйте его в `module.ts`.
Если модулю нужно хранить состояние, создайте класс контроллера в каталоге `lib/` и экспортируйте его в `module.ts`.
### Шаг 5: Валидация
### Шаг 5: Проверка
Перезапустите бота.
Перезапустите бота:
1. Проверьте логи на наличие "Loaded module: my-feature".
2. Убедитесь, что команда `/ping` появилась в Discord.
1. Найдите в логах строку «Loaded module: my-feature».
2. Убедитесь, что команда `/ping` появилась и работает в Discord.
{{% /steps %}}
## Шаблоны интеграции
| Паттерн | Сценарий использования | Компоненты |
| Шаблон | Назначение | Состав |
| :--- | :--- | :--- |
| **Простая команда** | Утилиты без состояния (Ping, Бросок кубиков) | Только `commands/` |
| **Сервис с состоянием** | Музыка, RPG, Экономика | `commands/` + `lib/Controller` |
| **Событийно-ориентированный** | Автомодерация, Логирование | Только `events/` |
| **Гибридный** | Сложные функции (ИИ-чат) | Все компоненты |
| **Простая команда** | Утилиты без сохранения состояния (`/ping`, бросок кубика) | Только `commands/` |
| **Сервис с состоянием** | Музыка, ролевые игры, экономика | `commands/` + `lib/Controller` |
| **Событийная логика** | Автомодерация, логирование | Только `events/` |
| **Гибридный модуль** | Сложные сценарии (например, ИИ-чат) | Все компоненты |
---
**См. также:**
- [Руководство Discord.js: Slash-команды](https://discordjs.guide/creating-your-bot/slash-commands.html)
- [Руководство Discord.js: слэш-команды](https://discordjs.guide/creating-your-bot/slash-commands.html)
@@ -1,39 +1,39 @@
---
title: Интерактивные голосовые функции
title: Голосовые функции
weight: 3
---
**Цель:** Реализовать сложные голосовые взаимодействия, которые учитывают границы серверов (гильдий) и управляют временными ресурсами.
**Цель:** реализовать голосовое взаимодействие с изоляцией ресурсов по серверам (гильдиям) и корректным управлением аудиосессиями.
## 1. Стратегия ограничения ресурсов
## 1. Изоляция ресурсов
Голосовые функции **ОБЯЗАТЕЛЬНО** должны быть ограничены рамками Гильдии (Guild).
Голосовые функции бота **обязательно** изолируются на уровне отдельного сервера (гильдии):
- **Паттерн:** Контроллер поддерживает `Map<GuildID, Player>`.
- **Архитектурный шаблон:** контроллер хранит соответствие `Map<GuildID, Player>`.
- **Поведение:**
- **Подключение (Join):** Создать Player для `Гильдии A`, если он еще не существует.
- **Отключение (Leave):** Уничтожить Player и освободить соединения.
- **Изоляция:** Команды в `Гильдии B` никогда не влияют на `Гильдию A`.
- **Подключение (Join):** создать `Player` для сервера A, если он ещё не существует.
- **Отключение (Leave):** удалить `Player` и освободить соединение.
- **Изоляция:** команды на сервере B никак не влияют на сервер A.
## 2. Оркестрация команд
## 2. Маршрутизация команд
Голосовые функции требуют набора команд, координируемых через Контроллер.
Голосовые функции опираются на набор команд, работу которых координирует контроллер:
| Команда | Действие | Логика Контроллера |
| Команда | Действие | Логика контроллера |
| :--- | :--- | :--- |
| `/join` | Подключиться к каналу | `createPlayer(guildId, channelId)` |
| `/play` | Добавить трек в очередь | `getPlayer(guildId).enqueue(track)` |
| `/stop` | Отключиться | `destroyPlayer(guildId)` |
| `/join` | Подключиться к голосовому каналу | `createPlayer(guildId, channelId)` |
| `/play` | Добавить трек в очередь | `getPlayer(guildId).enqueue(track)` |
| `/stop` | Отключиться от канала | `destroyPlayer(guildId)` |
## 3. Сохранение состояния
## 3. Управление состоянием
Аудиосессии эфемерны.
Аудиосессии по своей природе эфемерны:
- **Временное состояние:** Активный аудиопоток (Теряется при отключении).
- **Постоянное состояние:** Очередь / Плейлист (Сохраняется в Контроллере до перезапуска).
- **Временное состояние:** активный аудиопоток (сбрасывается при отключении).
- **Долговременное состояние:** очередь воспроизведения или плейлист (хранится в контроллере до перезапуска бота).
> [!TIP]
> **Устойчивость:** Разделяйте логику _Очереди_ и логику _Голосового соединения_. Это позволяет боту переподключаться без потери плейлиста пользователя.
> **Надёжность:** разделяйте логику очереди воспроизведения и логику голосового соединения. Тогда бот сможет переподключиться без потери пользовательского плейлиста.
## 4. Пример реализации
@@ -60,4 +60,4 @@ class MusicController {
**См. также:**
- [Руководство Discord.js Voice](https://discordjs.guide/voice/)
- [Руководство Discord.js по голосовым функциям](https://discordjs.guide/voice/)