Merged with backport-KarkasLite-into-main

This commit is contained in:
Maxim Slipenko 2024-08-19 13:24:05 +03:00
commit a7f1631869
167 changed files with 3948 additions and 603 deletions

2
.gitignore vendored
View File

@ -5,6 +5,6 @@ env
.venv .venv
venv venv
__pycache__ __pycache__
OCAB.db Karkas.db
config.yaml config.yaml
dist dist

8
AUTHORS Normal file
View File

@ -0,0 +1,8 @@
Руководитель проекта:
- Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru
Ведущие разработчики:
- Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com
Участники проекта:
- Илья Женецкий (@ilyazheprog)

8
AUTHORS_EN Normal file
View File

@ -0,0 +1,8 @@
Project manager:
- Semen Fomchenkov (@Armatik), e-mail: armatik@alt-gnome.ru
Leading developers:
- Maxim Slipenko (@Maks1m_S), e-mail: maxim@slipenko.com
Project participants:
- Ilya Zhenetsky (@ilyazheprog)

View File

@ -1,8 +1,8 @@
Руководитель проекта: Руководитель проекта:
- Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru - Семен Фомченков (@Armatik), e-mail: armatik@alt-gnome.ru
Ведущие разработчики: Ведущие разработчики:
- Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com - Максим Слипенко (@Maks1m_S), e-mail: maxim@slipenko.com
Участники проекта: Участники проекта:
- Илья Женецкий (@ilyazheprog) - Илья Женецкий (@ilyazheprog)

View File

@ -1,23 +1,23 @@
# OCAB - Open Chat Ai Bot # Karkas
## Что такое OCAB? ## Что такое Karkas?
OCAB - это платформа для разработки модульных Telegram-ботов, которая призвана упростить взаимодействие с чатами. Karkas - это платформа для разработки модульных Telegram-ботов, которая призвана упростить взаимодействие с чатами.
OCAB предоставляет возможность расширять функциональность бота с помощью интеграции различных модулей. Karkas предоставляет возможность расширять функциональность бота с помощью интеграции различных модулей.
Код платформы и набор стандартных модулей находятся в этом монорепозитории. Код платформы и набор стандартных модулей находятся в этом монорепозитории.
## Структура монорепозитория ## Структура монорепозитория
Монорепозиторий OCAB включает в себя: Монорепозиторий Karkas включает в себя:
* **Ядро OCAB (src/ocab_core):** Содержит основные компоненты платформы, такие как система управления модулями, * **Ядро Karkas (src/karkas_core):** Содержит основные компоненты платформы, такие как система управления модулями,
логирование и утилиты. логирование и утилиты.
* **Модули OCAB (src/ocab_modules):** Содержит стандартные и дополнительные модули, которые расширяют * **Модули Karkas (src/karkas_blocks):** Содержит стандартные и дополнительные модули, которые расширяют
функциональность ботов OCAB. функциональность ботов Karkas.
* **Пример бота (src/gnomik):** Пример реализации бота на платформе OCAB. * **Пример бота (src/gnomik):** Пример реализации бота на платформе Karkas.
## Модули ## Модули
Модули OCAB - это независимые компоненты, которые добавляют функциональность к боту. Модули Karkas - это независимые компоненты, которые добавляют функциональность к боту.
### Структура модуля ### Структура модуля
@ -26,19 +26,19 @@ OCAB предоставляет возможность расширять фун
### Стандартные модули ### Стандартные модули
Стандартные модули предоставляют базовые функции для работы бота: Стандартные модули предоставляют базовые функции для работы бота:
* [admin](src/ocab_modules/ocab_modules/standard/admin/README.md) - модуль для модерирования чата. * [admin](src/karkas_blocks/karkas_blocks/standard/admin/README.md) - модуль для модерирования чата.
* [roles](src/ocab_modules/ocab_modules/standard/roles/README.md) - модуль ролей пользователей. * [roles](src/karkas_blocks/karkas_blocks/standard/roles/README.md) - модуль ролей пользователей.
* [config](src/ocab_modules/ocab_modules/standard/config/README.md) - модуль управления конфигурацией бота. * [config](src/karkas_blocks/karkas_blocks/standard/config/README.md) - модуль управления конфигурацией бота.
* [database](src/ocab_modules/ocab_modules/standard/database/README.md) - модуль для работы с базой данных. * [database](src/karkas_blocks/karkas_blocks/standard/database/README.md) - модуль для работы с базой данных.
* [fsm_database_storage](src/ocab_modules/ocab_modules/standard/fsm_database_storage/README.md) - модуль для хранения состояний FSM в базе данных. * [fsm_database_storage](src/karkas_blocks/karkas_blocks/standard/fsm_database_storage/README.md) - модуль для хранения состояний FSM в базе данных.
* [filters](src/ocab_modules/ocab_modules/standard/filters/README.md) - модуль, предоставляющий фильтры для aiogram. * [filters](src/karkas_blocks/karkas_blocks/standard/filters/README.md) - модуль, предоставляющий фильтры для aiogram.
* [message_processing](src/ocab_modules/ocab_modules/standard/message_processing/README.md) - модуль обработки входящих сообщений. * [message_processing](src/karkas_blocks/karkas_blocks/standard/message_processing/README.md) - модуль обработки входящих сообщений.
* [miniapp](src/ocab_modules/ocab_modules/standard/miniapp/README.md) - модуль для реализации веб-интерфейса бота. * [miniapp](src/karkas_blocks/karkas_blocks/standard/miniapp/README.md) - модуль для реализации веб-интерфейса бота.
* [command_helper](src/ocab_modules/ocab_modules/standard/command_helper/README.md) - модуль для упрощения регистрации команд бота. * [command_helper](src/karkas_blocks/karkas_blocks/standard/command_helper/README.md) - модуль для упрощения регистрации команд бота.
* [info](src/ocab_modules/ocab_modules/standard/info/README.md) - модуль предоставления информации о пользователях и чатах. * [info](src/karkas_blocks/karkas_blocks/standard/info/README.md) - модуль предоставления информации о пользователях и чатах.
### Дополнительные официальные модули ### Дополнительные официальные модули
Дополнительные официальные модули разработаны командой OCAB и предоставляют расширенные возможности для бота: Дополнительные официальные модули разработаны командой Karkas и предоставляют расширенные возможности для бота:
* [yandexgpt](src/ocab_modules/ocab_modules/external/yandexgpt/README.md) - модуль для интеграции с нейросетью YandexGPT. * [yandexgpt](src/karkas_blocks/karkas_blocks/external/yandexgpt/README.md) - модуль для интеграции с нейросетью YandexGPT.
* [create_report_apps](src/ocab_modules/ocab_modules/external/create_report_apps/README.md) - модуль для создания отчетов об ошибках. * [create_report_apps](src/karkas_blocks/karkas_blocks/external/create_report_apps/README.md) - модуль для создания отчетов об ошибках.

View File

@ -1,10 +1,10 @@
## Настройка рабочего окружения ## Настройка рабочего окружения
Данная инструкция поможет вам настроить рабочее окружение для разработки OCAB. Данная инструкция поможет вам настроить рабочее окружение для разработки Karkas.
### Предварительные требования ### Предварительные требования
* **Python 3.12:** OCAB требует Python 3.12. * **Python 3.12:** Karkas требует Python 3.12.
* **VSCode:** Рекомендуется использовать VSCode для разработки. * **VSCode:** Рекомендуется использовать VSCode для разработки.
* **Git:** У вас должен быть установлен Git для клонирования репозитория. * **Git:** У вас должен быть установлен Git для клонирования репозитория.
@ -12,18 +12,18 @@
1. **Клонируйте репозиторий:** 1. **Клонируйте репозиторий:**
```bash ```bash
git clone https://gitflic.ru/project/armatik/ocab.git git clone https://gitflic.ru/project/alt-gnome/karkas.git
``` ```
2. **Откройте проект в VSCode:** 2. **Откройте проект в VSCode:**
* Откройте папку `ocab` в VSCode. * Откройте папку `karkas` в VSCode.
* VSCode автоматически предложит открыть проект как workspace, используя файл `ocab.code-workspace`. * VSCode автоматически предложит открыть проект как workspace, используя файл `karkas.code-workspace`.
Нажмите "Открыть Workspace", чтобы принять предложение. Нажмите "Открыть Workspace", чтобы принять предложение.
3. **Настройте Poetry:** 3. **Настройте Poetry:**
* Установите Poetry, следуя инструкциям на официальном сайте: [https://python-poetry.org/docs/](https://python-poetry.org/docs/). * Установите Poetry, следуя инструкциям на официальном сайте: [https://python-poetry.org/docs/](https://python-poetry.org/docs/).
* **Для каждого пакета:** * **Для каждого пакета:**
* Перейдите в папку пакета (например, `src/ocab_core`). * Перейдите в папку пакета (например, `src/karkas_core`).
* Выполните команду `poetry install`, чтобы установить зависимости пакета. * Выполните команду `poetry install`, чтобы установить зависимости пакета.
* Poetry создаст виртуальное окружение внутри папки пакета (`.venv`). * Poetry создаст виртуальное окружение внутри папки пакета (`.venv`).

View File

@ -16,7 +16,7 @@
"id": "standard.info", "id": "standard.info",
"name": "Info", "name": "Info",
"description": "Модуль с информацией", "description": "Модуль с информацией",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {
@ -50,7 +50,7 @@
- `author`: Автор модуля. - `author`: Автор модуля.
- `version`: Версия модуля в формате [SemVer](https://semver.org/). - `version`: Версия модуля в формате [SemVer](https://semver.org/).
- `privileged`: Булево значение, указывающее, является ли модуль привилегированным. - `privileged`: Булево значение, указывающее, является ли модуль привилегированным.
- `dependencies`: Объект, описывающий зависимости модуля от других **OCAB** модулей. - `dependencies`: Объект, описывающий зависимости модуля от других **Karkas** модулей.
- `required`: Обязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`. - `required`: Обязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`.
- `optional`: Необязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`. - `optional`: Необязательные зависимости. Ключ - идентификатор модуля, значение - версия или объект `DependencyInfo`.
- `pythonDependencies`: Объект, описывающий зависимости модуля от внешних Python пакетов. - `pythonDependencies`: Объект, описывающий зависимости модуля от внешних Python пакетов.
@ -80,7 +80,7 @@
- Модуль выполняется в доверенной среде на основе RestrictedPython (это накладывает ряд ограничений). - Модуль выполняется в доверенной среде на основе RestrictedPython (это накладывает ряд ограничений).
- Может импортировать только явно разрешенные модули, указанные в `pythonDependencies`, - Может импортировать только явно разрешенные модули, указанные в `pythonDependencies`,
а также несколько стандартных модулей, необходимых для работы. а также несколько стандартных модулей, необходимых для работы.
- Имеет доступ к пакету `ocab_core.modules_system.public_api` для взаимодействия с ботом. - Имеет доступ к пакету `karkas_core.modules_system.public_api` для взаимодействия с ботом.
**Привилегированный режим** (`privileged: true`): **Привилегированный режим** (`privileged: true`):
- Модуль выполняется без ограничений. - Модуль выполняется без ограничений.
@ -100,7 +100,7 @@
## Взаимодействие между модулями ## Взаимодействие между модулями
Модули могут взаимодействовать друг с другом через [API](../src/ocab_core/ocab_core/modules_system/public_api/__init__.py), Модули могут взаимодействовать друг с другом через [API](../src/karkas_core/karkas_core/modules_system/public_api/__init__.py),
предоставляемое системой управления модулями. предоставляемое системой управления модулями.
Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его

48
gitflic-ci.yaml Normal file
View File

@ -0,0 +1,48 @@
stages:
- lint
- build
lint-pre-commit:
stage: lint
image: python:3.12-bullseye
before_script:
- pip install pre-commit
scripts:
- pre-commit run --all-files
cache:
paths:
- .cache/pip
- .cache/pre-commit
.docker-dev-build-template:
before_script:
- docker info
- docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
scripts:
- |
cd ./src/${KARKAS_PROJECT}
export IMAGE_COMMIT=${IMAGE_NAME}:${CI_COMMIT_SHA}
export IMAGE_BRANCH=${IMAGE_NAME}:$(echo $CI_COMMIT_REF_NAME | sed 's/[^a-zA-Z0-9]/-/g')
docker build -t ${IMAGE_COMMIT} -t ${IMAGE_BRANCH} -f Dockerfile ../..
docker push ${IMAGE_COMMIT}
docker push ${IMAGE_BRANCH}
build-altlinux:
stage: build
image: docker:27.1.2
variables:
CI_REGISTRY: registry.gitflic.ru
IMAGE_NAME: registry.gitflic.ru/project/alt-gnome/karkas/altlinux
KARKAS_PROJECT: altlinux
extends: .docker-dev-build-template
build-gnomik:
stage: build
image: docker:27.1.2
variables:
CI_REGISTRY: registry.gitflic.ru
IMAGE_NAME: registry.gitflic.ru/project/alt-gnome/karkas/gnomik
KARKAS_PROJECT: gnomik
extends: .docker-dev-build-template

29
karkas.code-workspace Normal file
View File

@ -0,0 +1,29 @@
{
"folders": [
{
"name": "Karkas Monorepo Root",
"path": ".",
},
{
"name": "Karkas Blocks",
"path": "src/karkas_blocks"
},
{
"name": "Karkas Core",
"path": "src/karkas_core"
},
{
"name": "Gnomik",
"path": "src/gnomik"
},
{
"name": "ALT Linux",
"path": "src/altlinux"
}
],
"extensions": {
"recommendations": [
"ms-python.python"
]
},
}

View File

@ -1,25 +0,0 @@
{
"folders": [
{
"name": "OCAB Monorepo Root",
"path": ".",
},
{
"name": "OCAB Modules",
"path": "src/ocab_modules"
},
{
"name": "OCAB Core",
"path": "src/ocab_core"
},
{
"name": "Gnomik",
"path": "src/gnomik"
}
],
"extensions": {
"recommendations": [
"ms-python.python"
]
},
}

View File

@ -1,7 +1,7 @@
[tool.poetry] [tool.poetry]
name = "ocab-monorepo" name = "karkas-monorepo"
version = "2.0.0" version = "2.0.0"
description = "OCAB is a modular Telegram bot" description = "Karkas is a modular Telegram bot"
license = "GPL-3.0-only" license = "GPL-3.0-only"
authors = ["Семён Фомченков <s.fomchenkov@yandex.ru>"] authors = ["Семён Фомченков <s.fomchenkov@yandex.ru>"]
maintainers = [ maintainers = [
@ -11,13 +11,13 @@ maintainers = [
"Максим Слипенко <maxim@slipenko.com>" "Максим Слипенко <maxim@slipenko.com>"
] ]
readme = "README.md" readme = "README.md"
repository = "https://gitflic.ru/project/armatik/ocab" repository = "https://gitflic.ru/project/alt-gnome/karkas"
packages = [ packages = [
{ include = "scripts" } { include = "scripts" }
] ]
[tool.poetry.urls] [tool.poetry.urls]
"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN" "Bug Tracker" = "https://gitflic.ru/project/alt-gnome/karkas/issue?status=OPEN"
[tool.poetry.scripts] [tool.poetry.scripts]
test = 'scripts.test:main' test = 'scripts.test:main'

View File

@ -4,9 +4,9 @@ from pathlib import Path
def main(): def main():
pwd = Path().cwd() pwd = Path().cwd()
dir_core = pwd / "src" / "ocab_core" dir_core = pwd / "src" / "karkas_core"
dir_modules_standard = pwd / "src" / "ocab_modules" / "standard" dir_modules_standard = pwd / "src" / "karkas_blocks" / "standard"
dir_modules_external = pwd / "src" / "ocab_modules" / "external" dir_modules_external = pwd / "src" / "karkas_blocks" / "external"
json = { json = {
"core": str(dir_core), "core": str(dir_core),

View File

@ -4,14 +4,14 @@ import os
DEFAULTS = { DEFAULTS = {
"description": "Очень полезный модуль", "description": "Очень полезный модуль",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": "false", "privileged": "false",
} }
def create_module(args): def create_module(args):
module_dir = os.path.join("src/ocab_modules/standard", args.module_name) module_dir = os.path.join("src/karkas_blocks/standard", args.module_name)
os.makedirs(module_dir, exist_ok=True) os.makedirs(module_dir, exist_ok=True)
module_info = { module_info = {

25
src/altlinux/Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM python:3.12-slim as builder
RUN pip install poetry
RUN mkdir -p /app
COPY . /app
# Фикс
RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/karkas_blocks/pyproject.toml
WORKDIR /app/src/altlinux
RUN poetry lock && poetry install
FROM python:3.12-slim as base
# Copy the virtual environment separately to improve caching
COPY --from=builder /app/src/altlinux/.venv /app/.venv
COPY --from=builder /app/src/altlinux /app
WORKDIR /app
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "altlinux"]

View File

@ -0,0 +1,14 @@
**/Dockerfile
**/*.dockerignore
**/docker-compose.yml
**/.git
**/.gitignore
**/.venv
**/.mypy_cache
**/__pycache__/
src/gnomik/config.yaml
src/gnomik/database/*

46
src/altlinux/README.md Normal file
View File

@ -0,0 +1,46 @@
# ALT Linux
## Описание
Подготовленная версия Karkas Lite для интеграции в чат [Альт Линукс](https://t.me/alt_linux)
## Функционал
Список OCAB-модулей используемых в боте:
* report - Вызов администрации чата одной командой
* welcome - Автоматическая вариативная проверка пользователей на признаки бота или другой автоматической рекламной системы
* help - Получение информации об Karkas Lite
## Запуск
### Docker
1. Соберите Docker-образ:
```bash
docker build -t gnomik .
```
2. Запустите контейнер:
```bash
docker run -p 9000:9000 -v ./config.yaml:/app/config.yaml -v ./database:/app/database gnomik
```
Замените `./config.yaml` и `./database` на пути к вашим локальным файлам конфигурации и паки для базы данных.
### Вручную
1. Активируйте виртуальное окружение Gnomика:
```bash
poetry shell
```
2. Запустите бота:
```bash
python -m gnomik
```
## Конфигурация
Конфигурация бота находится в файле `config.yaml`.
## Модули
Список загружаемых модулей указан в файле `__main__.py`.

View File

@ -0,0 +1,25 @@
import asyncio
from importlib.metadata import version
from karkas_blocks import block_loader
from karkas_core import Karkas
async def main():
karkas = Karkas()
await karkas.init_app(
[
block_loader("standard", "config", safe=False),
block_loader("standard", "command_helper"),
# safe=False из-за super().__init__()
block_loader("standard", "filters", safe=False),
block_loader("standard", "report"),
block_loader("standard", "welcome", safe=False),
block_loader("standard", "help"),
],
metainfo={"app_version": version("altlinux")},
)
await karkas.start()
asyncio.run(main())

View File

@ -0,0 +1,7 @@
core:
mode: LONG_POLLING
token: xxx
filters:
approved_chat_id:
- -111111

View File

@ -0,0 +1,9 @@
version: '3'
services:
app:
build:
context: ../..
dockerfile: src/altlinux/Dockerfile
volumes:
- ./config.yaml:/app/config.yaml

2162
src/altlinux/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
[tool.poetry]
name = "altlinux"
version = "0.1.0"
description = ""
authors = [
"Максим Слипенко <maxim@slipenko.com>"
]
readme = "README.md"
[tool.poetry.dependencies]
python = "~3.12"
karkas-core = { extras=["webhook"], path = "../karkas_core", develop = true }
karkas-blocks = { path = "../karkas_blocks", develop = true }
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@ -6,9 +6,9 @@ COPY . /app
# Фикс # Фикс
RUN sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/gnomik/pyproject.toml && \ RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
sed -i '/ocab-modules = {/{s/, develop = true//}' /app/src/gnomik/pyproject.toml && \ sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
sed -i '/ocab-core = {/{s/, develop = true//}' /app/src/ocab_modules/pyproject.toml sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/karkas_blocks/pyproject.toml
WORKDIR /app/src/gnomik WORKDIR /app/src/gnomik
@ -16,6 +16,8 @@ RUN poetry lock && poetry install
FROM python:3.12-slim as base FROM python:3.12-slim as base
# Copy the virtual environment separately to improve caching
COPY --from=builder /app/src/gnomik/.venv /app/.venv
COPY --from=builder /app/src/gnomik /app COPY --from=builder /app/src/gnomik /app
WORKDIR /app WORKDIR /app

View File

@ -12,7 +12,7 @@ ALT Regular Gnome Community - открытое сообщество пользо
## Описание ## Описание
Gnomик - это чат-бот, разработанный на платформе Open Chat AI Bot (OCAB) для Telegram. Он предоставляет различные функции и возможности, помогающие пользователям операционной системы ALT Regular Gnome. Gnomик - это чат-бот для Telegram, разработанный на платформе Karkas. Он предоставляет различные функции и возможности, помогающие пользователям операционной системы ALT Regular Gnome.
## Функционал ## Функционал

View File

@ -1,26 +1,26 @@
import asyncio import asyncio
from ocab_core import OCAB from karkas_blocks import block_loader
from ocab_modules import module_loader from karkas_core import Karkas
async def main(): async def main():
ocab = OCAB() ocab = Karkas()
await ocab.init_app( await ocab.init_app(
[ [
module_loader("standard", "config", safe=False), block_loader("standard", "config", safe=False),
module_loader("standard", "database", safe=False), block_loader("standard", "database", safe=False),
module_loader("standard", "fsm_database_storage", safe=False), block_loader("standard", "fsm_database_storage", safe=False),
module_loader("standard", "roles", safe=False), block_loader("standard", "roles", safe=False),
module_loader("external", "yandexgpt", safe=False), block_loader("external", "yandexgpt", safe=False),
# #
module_loader("standard", "command_helper"), block_loader("standard", "command_helper"),
module_loader("standard", "info"), block_loader("standard", "info"),
module_loader("standard", "filters"), block_loader("standard", "filters"),
module_loader("external", "create_report_apps"), block_loader("external", "create_report_apps"),
module_loader("standard", "admin"), block_loader("standard", "admin"),
module_loader("standard", "message_processing"), block_loader("standard", "message_processing"),
module_loader("standard", "miniapp", safe=False), block_loader("standard", "miniapp", safe=False),
] ]
) )
await ocab.start() await ocab.start()

View File

@ -7,8 +7,8 @@ readme = "README.md"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "~3.12" python = "~3.12"
ocab-core = { extras=["webhook"], path = "../ocab_core", develop = true } karkas-core = { extras=["webhook"], path = "../karkas_core", develop = true }
ocab-modules = { path = "../ocab_modules", develop = true } karkas-blocks = { path = "../karkas_blocks", develop = true }
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]

View File

@ -0,0 +1,12 @@
# Karkas Blocks
Karkas Blocks содержит набор модулей для платформы Open Chat AI Bot (Karkas).
## Описание
Karkas - это платформа для создания чат-ботов Telegram. Модули - это расширения, которые добавляют функциональность ботам Karkas.
## Типы модулей
* **Стандартные модули (standard.*):** Предоставляют основные функции, такие как управление пользователями, ролями и настройками.
* **Дополнительные официальные модули (external.*):** Разработаны командой Karkas и предоставляют расширенные возможности, такие как интеграция с нейросетями, внешними сервисами и API.

View File

@ -0,0 +1 @@
from .lib import block_loader

View File

@ -10,7 +10,7 @@ from aiogram.types import (
ReplyKeyboardRemove, ReplyKeyboardRemove,
) )
from ocab_core.modules_system.public_api import Utils, get_fsm_context from karkas_core.modules_system.public_api import Utils, get_fsm_context
from .report import Report from .report import Report

View File

@ -10,7 +10,7 @@ from aiogram.types import (
Message, Message,
) )
from ocab_core.modules_system.public_api import get_module, register_router from karkas_core.modules_system.public_api import get_module, register_router
from .create_report import router as create_report_router from .create_report import router as create_report_router
from .create_report import start_report from .create_report import start_report

View File

@ -4,13 +4,13 @@ from typing import TYPE_CHECKING
from aiogram import Bot from aiogram import Bot
from aiogram.types import Message from aiogram.types import Message
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
from .yandexgpt import YandexGPT from .yandexgpt import YandexGPT
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.config import IConfig from karkas_blocks.standard.config import IConfig
from ocab_modules.standard.database.db_api import add_message as IAddMessage from karkas_blocks.standard.database.db_api import add_message as IAddMessage
config: "IConfig" = get_module( config: "IConfig" = get_module(
"standard.config", "standard.config",

View File

@ -1,9 +1,9 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.config import IConfig from karkas_blocks.standard.config import IConfig
config: "IConfig" = get_module("standard.config", "config") config: "IConfig" = get_module("standard.config", "config")

View File

@ -5,11 +5,11 @@ from typing import TYPE_CHECKING
import aiohttp import aiohttp
import requests import requests
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.config import IConfig from karkas_blocks.standard.config import IConfig
from ocab_modules.standard.database import db_api as IDbApi from karkas_blocks.standard.database import db_api as IDbApi
db_api: "IDbApi" = get_module("standard.database", "db_api") db_api: "IDbApi" = get_module("standard.database", "db_api")

View File

@ -0,0 +1,25 @@
import importlib
import os
from karkas_core.modules_system.loaders.fs_loader import FSLoader
from karkas_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
def get_module_directory(module_name):
spec = importlib.util.find_spec(module_name)
if spec is None:
raise ImportError(f"Module {module_name} not found")
module_path = spec.origin
if module_path is None:
raise ImportError(f"Module {module_name} has no origin path")
return os.path.dirname(module_path)
karkas_blocks_path = get_module_directory("karkas_blocks")
def block_loader(namespace: str, module_name: str, safe=True):
if not safe:
return UnsafeFSLoader(f"{karkas_blocks_path}/{namespace}/{module_name}")
else:
return FSLoader(f"{karkas_blocks_path}/{namespace}/{module_name}")

View File

@ -4,10 +4,10 @@ from typing import TYPE_CHECKING
from aiogram import Bot from aiogram import Bot
from aiogram.types import Message from aiogram.types import Message
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.config import IConfig from karkas_blocks.standard.config import IConfig
config: "IConfig" = get_module("standard.config", "config") config: "IConfig" = get_module("standard.config", "config")

View File

@ -2,12 +2,13 @@
"id": "standard.admin", "id": "standard.admin",
"name": "Admin", "name": "Admin",
"description": "Модуль для работы с админкой", "description": "Модуль для работы с админкой",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {
"required": { "required": {
"standard.filters": "^1.0.0" "standard.filters": "^1.0.0",
"standard.roles": "^1.0.0"
} }
} }
} }

View File

@ -1,4 +1,4 @@
from ocab_core.modules_system.public_api import register_router from karkas_core.modules_system.public_api import register_router
from .routers import router from .routers import router

View File

@ -2,7 +2,7 @@
from aiogram import F, Router from aiogram import F, Router
from aiogram.filters import Command from aiogram.filters import Command
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
from .handlers import ( from .handlers import (
chat_not_in_approve_list, chat_not_in_approve_list,

View File

@ -16,7 +16,7 @@
## Пример ## Пример
```python ```python
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
register_command = get_module("standard.command_helper", "register_command") register_command = get_module("standard.command_helper", "register_command")

View File

@ -0,0 +1 @@
from .main import get_user_commands, module_late_init, register_command

View File

@ -2,13 +2,8 @@
"id": "standard.command_helper", "id": "standard.command_helper",
"name": "Command helper", "name": "Command helper",
"description": "Модуль для отображения команд при вводе '/'", "description": "Модуль для отображения команд при вводе '/'",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {}
"required": {
"standard.roles": "^1.0.0",
"standard.database": "^1.0.0"
}
}
} }

View File

@ -0,0 +1,42 @@
from aiogram.types import BotCommand
from karkas_core.modules_system.public_api import set_my_commands
commands = dict()
def register_command(command, description, role="USER"):
if role not in commands:
commands[role] = dict()
commands[role][command] = {
"description": description,
}
async def set_user_commands():
bot_commands = []
if "USER" in commands:
user_commands = commands["USER"]
for command in user_commands:
bot_commands.append(
BotCommand(
command=command,
description=user_commands[command]["description"],
)
)
# log(bot_commands)
await set_my_commands(
bot_commands,
)
def get_user_commands():
if "USER" in commands:
return commands["USER"].copy()
return {}
async def module_late_init():
await set_user_commands()

View File

@ -18,7 +18,7 @@
## Пример ## Пример
```python ```python
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
config = get_module("standard.config", "config") config = get_module("standard.config", "config")

View File

@ -66,7 +66,7 @@ class ConfigManager:
def _get_module_id(self): def _get_module_id(self):
caller_frame = inspect.currentframe().f_back.f_back caller_frame = inspect.currentframe().f_back.f_back
caller_globals = caller_frame.f_globals caller_globals = caller_frame.f_globals
module_id = caller_globals.get("__ocab_module_id__") module_id = caller_globals.get("__karkas_block_id__")
return module_id return module_id
def mass_set(self, updates: Dict[str, Any]): def mass_set(self, updates: Dict[str, Any]):
@ -84,6 +84,7 @@ class ConfigManager:
key: str, key: str,
value_type: str, value_type: str,
options: List[Any] = None, options: List[Any] = None,
multiple: bool = False,
default_value=None, default_value=None,
editable: bool = True, editable: bool = True,
shared: bool = False, shared: bool = False,
@ -101,6 +102,7 @@ class ConfigManager:
self._metadata[key] = { self._metadata[key] = {
"type": value_type, "type": value_type,
"multiple": multiple,
"options": options, "options": options,
"default_value": default_value, "default_value": default_value,
"visible": visible, "visible": visible,

View File

@ -2,7 +2,7 @@
"id": "standard.config", "id": "standard.config",
"name": "Config YAML", "name": "Config YAML",
"description": "Модуль для работы с конфигурационным файлом бота (YAML)", "description": "Модуль для работы с конфигурационным файлом бота (YAML)",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": true, "privileged": true,
"dependencies": { "dependencies": {

View File

@ -1,4 +1,4 @@
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
from .config import config from .config import config
from .miniapp_ui import get_miniapp_blueprint from .miniapp_ui import get_miniapp_blueprint

View File

@ -12,10 +12,10 @@ try:
except ImportError: except ImportError:
DASH_AVAILABLE = False DASH_AVAILABLE = False
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.roles import Roles as IRoles from karkas_blocks.standard.roles import Roles as IRoles
def create_control(key: str, config: ConfigManager): def create_control(key: str, config: ConfigManager):

View File

@ -1,6 +1,6 @@
import unittest import unittest
from src.ocab_modules.standard.config.config import get_config from src.karkas_blocks.standard.config.config import get_config
yaml_load = get_config(is_test=True) yaml_load = get_config(is_test=True)

View File

@ -1,6 +1,6 @@
## Модуль DataBase ## Модуль DataBase
Модуль DataBase предназначен для ведения и работы с базами данных OCAB. Модуль DataBase предназначен для ведения и работы с базами данных Karkas.
Модуль содержит в себе следующие таблицы: Модуль содержит в себе следующие таблицы:

View File

@ -16,12 +16,12 @@ def connect_database(is_test: bool = False, module: str | None = None):
raise NotExpectedModuleName() raise NotExpectedModuleName()
db_path = "database" db_path = "database"
database = pw.SqliteDatabase(f"{db_path}/OCAB.db") database = pw.SqliteDatabase(f"{db_path}/Karkas.db")
database_proxy.initialize(database) database_proxy.initialize(database)
database.connect() database.connect()
create_tables(database) create_tables(database)
return database, f"{db_path}/OCAB.db" return database, f"{db_path}/Karkas.db"
def create_tables(db: pw.SqliteDatabase): def create_tables(db: pw.SqliteDatabase):

View File

@ -2,7 +2,7 @@
"id": "standard.database", "id": "standard.database",
"name": "Database", "name": "Database",
"description": "Модуль для работы с БД", "description": "Модуль для работы с БД",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": true, "privileged": true,
"dependencies": {} "dependencies": {}

View File

@ -16,7 +16,7 @@
```python ```python
from aiogram import Router from aiogram import Router
from ocab_core.modules_system.public_api import get_module from karkas_core.modules_system.public_api import get_module
ChatModerOrAdminFilter = get_module("standard.filters", "ChatModerOrAdminFilter") ChatModerOrAdminFilter = get_module("standard.filters", "ChatModerOrAdminFilter")

View File

@ -1,4 +1,5 @@
from .filters import ( from .filters import (
ChatIDFilter,
ChatModerOrAdminFilter, ChatModerOrAdminFilter,
ChatNotInApproveFilter, ChatNotInApproveFilter,
chat_not_in_approve, chat_not_in_approve,

View File

@ -0,0 +1,84 @@
from typing import TYPE_CHECKING
from aiogram import Bot
from aiogram.filters import BaseFilter
from aiogram.types import Message
from typing_extensions import deprecated
from karkas_core.modules_system.public_api import get_module
if TYPE_CHECKING:
from karkas_blocks.standard.config import IConfig
from karkas_blocks.standard.roles import Roles as IRoles
config: "IConfig" = get_module("standard.config", "config")
try:
Roles: "type[IRoles]" = get_module("standard.roles", "Roles")
ROLES_MODULE_LOADED = True
except Exception:
ROLES_MODULE_LOADED = False
pass
def module_init():
config.register(
"filters::approved_chat_id", "int", multiple=True, shared=True, default_value=[]
)
config.register("filters::default_chat_tag", "string", shared=True)
def get_approved_chat_id() -> list:
return config.get("filters::approved_chat_id")
@deprecated("Use ChatIDFilter or own implementation")
def chat_not_in_approve(message: Message) -> bool:
chat_id = message.chat.id
if chat_id in get_approved_chat_id():
# log(f"Chat in approve list: {chat_id}")
return False
else:
# log(f"Chat not in approve list: {chat_id}")
return True
class ChatIDFilter(BaseFilter):
def __init__(self, blacklist=False, approved_chats=None) -> None:
self.blacklist = blacklist
self.approved_chats = approved_chats
super().__init__()
async def __call__(self, message: Message, bot: Bot) -> bool:
chat_id = message.chat.id
approved_chats = self.approved_chats or get_approved_chat_id()
# Если список для фильтрации пуст - разрешаем всем.
if len(approved_chats) == 0:
return True
res = chat_id in approved_chats
return res ^ (self.blacklist)
class ChatNotInApproveFilter(ChatIDFilter):
def __init__(self) -> None:
super().__init__(allow=False)
class ChatModerOrAdminFilter(BaseFilter):
async def __call__(self, message: Message, bot: Bot) -> bool:
if not ROLES_MODULE_LOADED:
raise Exception("Roles module not loaded")
user_id = message.from_user.id
roles = Roles()
admins = await bot.get_chat_administrators(message.chat.id)
return (
await roles.check_admin_permission(user_id)
or await roles.check_moderator_permission(user_id)
or any(user_id == admin.user.id for admin in admins)
)

View File

@ -2,13 +2,15 @@
"id": "standard.filters", "id": "standard.filters",
"name": "Filters", "name": "Filters",
"description": "Модуль с фильтрами", "description": "Модуль с фильтрами",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": true,
"dependencies": { "dependencies": {
"required": { "required": {
"standard.roles": "^1.0.0",
"standard.config": "^1.0.0" "standard.config": "^1.0.0"
},
"optional": {
"standard.roles": "^1.0.0"
} }
} }
} }

View File

@ -4,11 +4,11 @@ from typing import TYPE_CHECKING, Any, Dict, Optional
from aiogram.fsm.state import State from aiogram.fsm.state import State
from aiogram.fsm.storage.base import BaseStorage, StorageKey from aiogram.fsm.storage.base import BaseStorage, StorageKey
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
from ocab_core.modules_system.public_api.public_api import set_fsm from karkas_core.modules_system.public_api.public_api import set_fsm
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.database.repositories import ( from karkas_blocks.standard.database.repositories import (
FSMDataRepository as IFSMDataRepository, FSMDataRepository as IFSMDataRepository,
) )

View File

@ -2,7 +2,7 @@
"id": "standard.fsm_database_storage", "id": "standard.fsm_database_storage",
"name": "FSM Database Storage", "name": "FSM Database Storage",
"description": "Очень полезный модуль", "description": "Очень полезный модуль",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {

View File

@ -0,0 +1 @@
from .main import module_init

View File

@ -0,0 +1,21 @@
{
"id": "standard.help",
"name": "Help",
"description": "Модуль для вывода /help сообщения",
"author": "Karkas Team",
"version": "1.0.0",
"privileged": false,
"dependencies": {
"required": {
"standard.config": "^1.0.0"
},
"optional": {
"standard.command_helper": "^1.0.0"
}
},
"pythonDependencies": {
"required": {
"string": "*"
}
}
}

View File

@ -0,0 +1,81 @@
import string
from typing import TYPE_CHECKING
from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
from karkas_core.modules_system.public_api import (
get_metainfo,
get_module,
register_router,
)
if TYPE_CHECKING:
from karkas_blocks.standard.config import IConfig
config: "IConfig" = get_module("standard.config", "config")
try:
(register_command, get_user_commands) = get_module(
"standard.command_helper", ["register_command", "get_user_commands"]
)
COMMAND_HELPER_MODULE_LOADED = True
except Exception:
COMMAND_HELPER_MODULE_LOADED = False
pass
FOOTER = """===
Разработано командой ALT Gnome Infrastructure в рамках проекта Каркас.
Исходный код: https://gitflic.ru/project/alt-gnome/karkas
Оставить репорт: https://gitflic.ru/project/alt-gnome/karkas/issue/create
Руководитель проекта: Семен Фомченков
Ведущий разработчик: Максим Слипенко
Версия: $version
"""
def format_commands(commands_dict):
formatted_commands = []
for command, details in commands_dict.items():
formatted_commands.append(f"/{command} - {details['description']}")
return "\n".join(formatted_commands)
async def help(message: Message):
commands = ""
version = ""
if COMMAND_HELPER_MODULE_LOADED:
commands = format_commands(get_user_commands())
metainfo = get_metainfo()
if "app_version" in metainfo:
version = metainfo["app_version"]
await message.reply(
string.Template(config.get("help::message") + "\n\n" + FOOTER).substitute(
commands=commands, version=version or "не указана"
)
)
async def module_init():
config.register(
"help::message",
"string",
default_value="$commands",
)
router = Router()
router.message.register(help, Command("help"))
register_router(router)
if COMMAND_HELPER_MODULE_LOADED:
register_command("help", "Cправка")

View File

@ -5,11 +5,11 @@ from typing import TYPE_CHECKING
from aiogram import Bot from aiogram import Bot
from aiogram.types import Message from aiogram.types import Message
from ocab_core.modules_system.public_api import get_module, log from karkas_core.modules_system.public_api import get_module, log
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.database import db_api as IDbApi from karkas_blocks.standard.database import db_api as IDbApi
from ocab_modules.standard.roles import Roles as IRoles from karkas_blocks.standard.roles import Roles as IRoles
db_api: "IDbApi" = get_module( db_api: "IDbApi" = get_module(
"standard.database", "standard.database",

View File

@ -2,7 +2,7 @@
"id": "standard.info", "id": "standard.info",
"name": "Info", "name": "Info",
"description": "Модуль с информацией", "description": "Модуль с информацией",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {

View File

@ -1,7 +1,7 @@
from aiogram import Router from aiogram import Router
from aiogram.filters import Command from aiogram.filters import Command
from ocab_core.modules_system.public_api import get_module, register_router from karkas_core.modules_system.public_api import get_module, register_router
from .handlers import get_chat_info, get_user_info from .handlers import get_chat_info, get_user_info

View File

@ -2,7 +2,7 @@
"id": "standard.message_processing", "id": "standard.message_processing",
"name": "Info", "name": "Info",
"description": "Модуль с информацией", "description": "Модуль с информацией",
"author": "OCAB Team", "author": "Karkas Team",
"version": "1.0.0", "version": "1.0.0",
"privileged": false, "privileged": false,
"dependencies": { "dependencies": {

View File

@ -4,10 +4,10 @@ from typing import TYPE_CHECKING
from aiogram import Bot, F, Router, types from aiogram import Bot, F, Router, types
from ocab_core.modules_system.public_api import get_module, log, register_router from karkas_core.modules_system.public_api import get_module, log, register_router
if TYPE_CHECKING: if TYPE_CHECKING:
from ocab_modules.standard.config import IConfig from karkas_blocks.standard.config import IConfig
config: "IConfig" = get_module("standard.config", "config") config: "IConfig" = get_module("standard.config", "config")

Some files were not shown because too many files have changed in this diff Show More