Initial commit.

This commit is contained in:
Fjerkroa Auto 2023-03-21 18:25:14 +01:00
commit 5054cac49b
14 changed files with 246 additions and 0 deletions

6
.flake8 Normal file
View File

@ -0,0 +1,6 @@
[flake8]
exclude = .git,__pycache__,.venv
per-file-ignores = __init__.py:F401
max-line-length = 140
max-complexity = 10
select = B,C,E,F,W,T4,B9

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
__pycache__/
*.pyc
*.pyo
*.egg-info/
dist/
build/

11
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,11 @@
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.1.1'
hooks:
- id: mypy
args: [--config-file=mypy.ini]
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# Fjerkroa bot
A simple Discord bot that uses OpenAI's GPT to chat with users.
## Installation
1. Install the package using pip:
```
pip install fjerkroa-bot
```
2. Create a `bot.py` file with the following content, replacing the tokens with your own:
```python
from discord_gpt_bot import main
main.DISCORD_BOT_TOKEN = "your_discord_bot_token"
main.OPENAI_API_KEY = "your_openai_api_key"
main.run_bot()
```
3. Run the bot:
```
python bot.py
```

1
fjerkroa_bot/__init__.py Normal file
View File

@ -0,0 +1 @@
from .discord_bot import FjerkroaBot, main

View File

@ -0,0 +1,74 @@
import sys
import argparse
import json
import discord
from discord import Message
from discord.ext import commands
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ConfigFileHandler(FileSystemEventHandler):
def __init__(self, on_modified):
self._on_modified = on_modified
def on_modified(self, event):
self._on_modified(event)
class FjerkroaBot(commands.Bot):
def __init__(self, config_file: str):
assert not hasattr(self, 'config_file')
assert not hasattr(self, 'config')
assert not hasattr(self, 'observer')
assert not hasattr(self, 'file_handler')
self.config_file = config_file
self.config = self.load_config(self.config_file)
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
self.observer = Observer()
self.file_handler = ConfigFileHandler(self.on_config_file_modified)
self.observer.schedule(self.file_handler, path=".", recursive=False)
self.observer.start()
super().__init__(command_prefix="!", case_insensitive=True, intents=intents)
@classmethod
def load_config(self, config_file: str = "config.json"):
with open(config_file, "r") as file:
return json.load(file)
def on_config_file_modified(self, event):
if event.src_path == self.config_file:
self.config = self.load_config(self.config_file)
async def on_ready(self):
print(f"We have logged in as {self.user}")
async def on_message(self, message: Message) -> None:
await message.channel.send("Hello!")
async def close(self):
self.observer.stop()
await super().close()
def main() -> int:
from .logging import setup_logging
setup_logging()
parser = argparse.ArgumentParser(description='Fjerkroa AI bot')
parser.add_argument('--config', type=str, default='config.json', help='Config file.')
args = parser.parse_args()
config = FjerkroaBot.load_config(args.config)
bot = FjerkroaBot(args.config)
bot.run(config["discord_token"])
return 0
if __name__ == "__main__":
sys.exit(main())

11
fjerkroa_bot/logging.py Normal file
View File

@ -0,0 +1,11 @@
import sys
import logging
def setup_logging():
logging_handler = logging.StreamHandler(stream=sys.stdout)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging_handler],
)

7
mypy.ini Normal file
View File

@ -0,0 +1,7 @@
[mypy]
files = fjerkroa_bot, tests
ignore_missing_imports = True
strict_optional = True
warn_unused_ignores = True
warn_redundant_casts = True
warn_unused_configs = True

24
pyproject.toml Normal file
View File

@ -0,0 +1,24 @@
[build-system]
requires = ["setuptools", "wheel"]
[tool.mypy]
files = ["fjerkroa_bot", "tests"]
[tool.flake8]
max-line-length = 140
max-complexity = 10
ignore = [
"E203",
"E266",
"E501",
"W503",
]
exclude = [
".git",
".mypy_cache",
".pytest_cache",
"__pycache__",
"build",
"dist",
"venv",
]

10
requirements.txt Normal file
View File

@ -0,0 +1,10 @@
discord.py
openai
aiohttp
mypy
flake8
pre-commit
pytest
setuptools
wheel
watchdog

15
setup.py Normal file
View File

@ -0,0 +1,15 @@
from setuptools import setup, find_packages
setup(name='fjerkroa-bot',
version='2.0',
packages=find_packages(),
entry_points={'console_scripts': ['fjerkroa_bot = fjerkroa_bot:main']},
test_suite="tests",
install_requires=["discord.py", "openai"],
author="Oleksandr Kozachuk",
author_email="ddeus.lp@mailnull.com",
description="A simple Discord bot that uses OpenAI's GPT to chat with users",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/ok2/fjerkroa-bot",
classifiers=["Development Status :: 3 - Alpha", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3"])

6
setupenv.sh Normal file
View File

@ -0,0 +1,6 @@
export HOME=/home/pi
export PATH=$HOME/.pyenv/bin:$HOME/.pyenv/shims:$PATH
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
pyenv activate py311

0
tests/__init__.py Normal file
View File

50
tests/test_main.py Normal file
View File

@ -0,0 +1,50 @@
import unittest
import json
from unittest.mock import Mock, PropertyMock, MagicMock, AsyncMock, patch, mock_open
from fjerkroa_bot import FjerkroaBot
from discord import User, Message, TextChannel
class TestBotBase(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
self.mock_response = Mock()
self.mock_response.choices = [
Mock(text="Nice day today!")
]
self.config_data = {
"openai_key": "OPENAIKEY",
"engine": "gpt-4",
"max_tokens": 1024,
"n": 1,
"temperature": 0.9,
}
self.history_data = []
class TestFunctionality(TestBotBase):
def test_load_config(self):
with patch('builtins.open', mock_open(read_data=json.dumps(self.config_data))):
result = FjerkroaBot.load_config('config.json')
self.assertEqual(result, self.config_data)
async def test_on_message_event(self):
with patch.object(FjerkroaBot, 'load_config', new=lambda s, c: self.config_data), \
patch.object(FjerkroaBot, 'user', new_callable=PropertyMock) as mock_user:
mock_user.return_value = MagicMock(spec=User)
mock_user.return_value.id = 12
bot = FjerkroaBot('config.json')
message = MagicMock(spec=Message)
message.content = "Hello, how are you?"
message.author = AsyncMock(spec=User)
message.author.id = 123
message.author.bot = False
message.channel = AsyncMock(spec=TextChannel)
message.channel.send = AsyncMock()
await bot.on_message(message)
message.channel.send.assert_called_once_with("Hello!")
if __name__ == "__mait__":
unittest.main()