20 Commits

Author SHA1 Message Date
AlberLC
f6093ec01e Fix resource file resolution 2022-03-17 03:50:33 +01:00
AlberLC
99d84a5d35 Fix query place with coordinates 2022-02-21 00:58:56 +01:00
AlberLC
02d4965efa Fix CommonWords property name 2022-02-11 21:42:11 +01:00
AlberLC
e41338b5f6 Update workflows 2022-02-04 23:32:43 +01:00
AlberLC
47e371f270 Update README.rst 2022-02-02 01:46:16 +01:00
AlberLC
5746e99b3f Update README.rst 2022-02-02 01:43:17 +01:00
AlberLC
e1c14f7512 Update README.rst 2022-02-02 01:40:47 +01:00
AlberLC
503dfb4215 Update README.rst 2022-02-02 01:40:10 +01:00
AlberLC
a37c2ee1d7 Fix error message when inline weather 2022-01-31 06:22:02 +01:00
AlberLC
449df672b5 Update tests 2022-01-27 03:16:44 +01:00
AlberLC
d3b8c4f821 Update requirements.txt 2022-01-27 03:16:34 +01:00
AlberLC
acbd0e5ad1 Update requirements.txt 2022-01-24 05:01:57 +01:00
AlberLC
a0c693f5eb Improve string parse 2022-01-24 04:23:37 +01:00
AlberLC
5a500e71e3 Update Dockerfile 2022-01-23 01:35:42 +01:00
AlberLC
d6cdc1436f Add docker files 2022-01-21 20:07:46 +01:00
AlberLC
b9e61b296d Fix weather keywords 2022-01-18 22:05:20 +01:00
AlberLC
35583088ab Fix requirements.txt 2022-01-16 19:34:17 +01:00
AlberLC
73f2d4c485 Fix requirements.txt 2022-01-16 18:37:02 +01:00
AlberLC
a8cf321140 Fix requirements.txt encoding 2022-01-16 16:01:41 +01:00
AlberLC
944e473fac Fix .env load 2022-01-16 05:17:38 +01:00
10 changed files with 91 additions and 43 deletions

View File

@@ -22,10 +22,10 @@ jobs:
- name: Update setup.cfg
run: |
sed -i "
s/{project_name}/${{ github.event.repository.name }}/g;
s/{project_version}/${{ github.ref_name }}/g;
s/{author}/${{ github.repository_owner }}/g;
s/{description}/${{ github.event.repository.description }}/g
s|{project_name}|${{ github.event.repository.name }}|g;
s|{project_version}|${{ github.ref_name }}|g;
s|{author}|${{ github.repository_owner }}|g;
s|{description}|${{ github.event.repository.description }}|g
" setup.cfg
- name: Build package

10
Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM flanaganvaquero/flanawright
WORKDIR /application
COPY flanabot flanabot
COPY venv/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
ENV PYTHONPATH=/application
CMD python3.10 flanabot/main.py

View File

@@ -3,7 +3,9 @@ FlanaBot
|license| |project_version| |python_version|
Flanagan's bot.
Bot based on `github.com/AlberLC/multibot`_ to manage Discord, Telegram and Twitch chats, moderate them and add functionalities.
|
Installation
------------
@@ -14,6 +16,22 @@ Python 3.10 or higher is required.
pip install flanabot
|
Features
--------
- Talks to users.
- Delete message batches.
- It works both in groups and in private chats.
- Understands numbers and amounts of time textually expressed (useful for deleting a message batch or saying "flanabot ban john for one hour and 20 minutes").
- Shows interactive via buttons charts of past, current and forecast weather.
- Change user roles temporarily or forever.
- Mute users temporarily or forever.
- Ban users temporarily or forever.
- Configurable default behavior for each chat, just talk to him to configure it.
- Get media from twitter, instagram and tiktok and send it to the chat. From tiktok also obtains data about the song that is playing in the video.
.. |license| image:: https://img.shields.io/github/license/AlberLC/flanabot?style=flat
:target: https://github.com/AlberLC/flanabot/blob/main/LICENSE
@@ -26,3 +44,5 @@ Python 3.10 or higher is required.
.. |python_version| image:: https://img.shields.io/pypi/pyversions/flanabot
:target: https://www.python.org/downloads/
:alt: PyPI - Python Version
.. _github.com/AlberLC/multibot: https://github.com/AlberLC/multibot

17
docker-compose.yaml Normal file
View File

@@ -0,0 +1,17 @@
services:
flanabot:
image: flanaganvaquero/flanabot
build: .
env_file:
- .env
mongodb:
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
volumes:
- mongodata:/data/db
volumes:
mongodata:

View File

@@ -3,7 +3,7 @@ import datetime
import itertools
import pprint
import random
import time
import time as time_module
from abc import ABC
from asyncio import Future
from typing import Iterable, Iterator, Type
@@ -36,7 +36,7 @@ class FlanaBot(MultiBot, ABC):
def _add_handlers(self):
super()._add_handlers()
self.register(self._on_bye, constants.KEYWORDS['bye'], min_ratio=1)
self.register(self._on_bye, constants.KEYWORDS['bye'])
self.register(self._on_config_list_show, constants.KEYWORDS['config'])
self.register(self._on_config_list_show, constants.KEYWORDS['help'])
@@ -87,6 +87,7 @@ class FlanaBot(MultiBot, ABC):
self.register(self._on_hello, constants.KEYWORDS['hello'])
self.register(self._on_mute, constants.KEYWORDS['mute'])
self.register(self._on_mute, (('haz', 'se'), constants.KEYWORDS['mute']))
self.register(self._on_mute, (constants.KEYWORDS['deactivate'], constants.KEYWORDS['unmute']))
self.register(self._on_mute, (constants.KEYWORDS['deactivate'], constants.KEYWORDS['sound']))
@@ -303,7 +304,7 @@ class FlanaBot(MultiBot, ABC):
async def _search_medias(self, message: Message) -> OrderedSet[Media]:
bot_state_message: Message | None = None
start_time = time.perf_counter()
start_time = time_module.perf_counter()
results: Future = asyncio.gather(
twitter.get_medias(message.text),
@@ -314,7 +315,7 @@ class FlanaBot(MultiBot, ABC):
if not message.is_inline and (self.is_bot_mentioned(message) or not message.chat.is_group):
while not results.done():
if constants.SCRAPING_MESSAGE_WAITING_TIME <= time.perf_counter() - start_time:
if constants.SCRAPING_MESSAGE_WAITING_TIME <= time_module.perf_counter() - start_time:
bot_state_message = await self.send(random.choice(constants.SCRAPING_PHRASES), message)
break
await asyncio.sleep(0.1)
@@ -567,21 +568,23 @@ class FlanaBot(MultiBot, ABC):
user_names_with_at_sign = {user.name.lower() for user in message.chat.users}
user_names_without_at_sign = {user.name.lower().replace('@', '') for user in message.chat.users}
original_text_words = flanautils.remove_accents(message.text.lower())
original_text_words = original_text_words.replace(',', ' ').replace(';', ' ').replace('-', ' -')
original_text_words = flanautils.translate(
original_text_words,
{symbol: None for symbol in set(flanautils.SYMBOLS) - {'-', '.'}}
).split()
place_words = (
OrderedSet(original_text_words)
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['show'], min_ratio=0.8).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['weather_chart'], min_ratio=0.8).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['date'], min_ratio=0.8).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['thanks'], min_ratio=0.8).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['show'], min_ratio=0.85).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['weather_chart'], min_ratio=0.85).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['date'], min_ratio=0.85).keys()
- flanautils.cartesian_product_string_matching(original_text_words, constants.KEYWORDS['thanks'], min_ratio=0.85).keys()
- user_names_with_at_sign
- user_names_without_at_sign
- flanautils.CommonWords.words
- flanautils.CommonWords.all_words
)
if not place_words:
if not message.is_inline:
await self.send_error(random.choice(('¿Tiempo dónde?', 'Indica el sitio.', 'Y el sitio?', 'y el sitio? me lo invento?')), message)
return
@@ -589,7 +592,8 @@ class FlanaBot(MultiBot, ABC):
place_words.insert(0, 'calle')
place_query = ' '.join(place_words)
if len(place_query) >= constants.MAX_PLACE_QUERY_LENGTH:
await self.send_error(Media('resources/mucho_texto.png'), message)
if not message.is_inline:
await self.send_error(Media(str(flanautils.resolve_path('resources/mucho_texto.png'))), message, send_as_file=False)
return
if show_progress_state:
bot_state_message = await self.send(f'Buscando "{place_query}" en el mapa 🧐...', message)

View File

@@ -52,8 +52,8 @@ HELLO_PHRASES = ('alo', 'aloh', 'buenas', 'Hola.', 'hello', 'hey', 'hi', 'hola',
KEYWORDS = {
'activate': ('activa', 'activar', 'activate', 'deja', 'dejale', 'devuelve', 'devuelvele', 'enable', 'encender',
'enciende', 'habilita', 'habilitar'),
'bye': ('adieu', 'adio', 'adiooooo', 'adios', 'agur', 'buenas', 'bye', 'cama', 'chao', 'dias', 'farewell',
'goodbye', 'hasta', 'luego', 'noches', 'pronto', 'taluego', 'taluegorl', 'tenga', 'vemos', 'vista', 'voy'),
'bye': ('adieu', 'adio', 'adiooooo', 'adios', 'agur', 'buenas', 'bye', 'cama', 'chao', 'farewell', 'goodbye',
'hasta', 'luego', 'noches', 'pronto', 'taluego', 'taluegorl', 'tenga', 'vemos', 'vista', 'voy'),
'change': ('alter', 'alternar', 'alternate', 'cambiar', 'change', 'default', 'defecto', 'edit', 'editar',
'exchange', 'modificar', 'modify', 'permutar', 'predeterminado', 'shift', 'swap', 'switch', 'turn',
'vary'),
@@ -96,8 +96,8 @@ KEYWORDS = {
'cloudless', 'cloudy', 'cold', 'congelar', 'congelado', 'denbora', 'despejado', 'diluvio', 'frio',
'frost', 'hielo', 'humedad', 'llover', 'llueva', 'llueve', 'lluvia', 'nevada', 'nieva', 'nieve',
'nube', 'nubes', 'nublado', 'meteorologia', 'rain', 'snow', 'snowfall', 'snowstorm', 'sol',
'solano', 'storm', 'sun', 'temperatura', 'tempo', 'tiempo', 'tormenta', 've', 'ventisca',
'weather', 'wetter')
'solano', 'storm', 'sun', 'temperatura', 'tempo', 'tiempo', 'tormenta', 'ventisca', 'weather',
'wetter')
}
RECOVER_PHRASES = (

View File

@@ -1,14 +1,15 @@
import asyncio
import os
import flanautils
os.environ |= flanautils.find_environment_variables('../.env')
import asyncio
from flanabot.bots.flana_tele_bot import FlanaTeleBot
async def main():
os.environ |= flanautils.find_environment_variables('../.env')
flana_tele_bot = FlanaTeleBot()
await asyncio.gather(

Binary file not shown.

0
tests/unit/__init__.py Normal file
View File

View File

@@ -1,16 +1,21 @@
import os
import flanautils
os.environ |= flanautils.find_environment_variables('../.env')
import unittest
from typing import Iterable
from flanabot import constants
import flanautils
from flanabot.bots.flana_bots.flana_tele_bot import FlanaTeleBot
from multibot import constants as multibot_constants
from flanabot.bots.flana_tele_bot import FlanaTeleBot
class TestParseCallbacks(unittest.TestCase):
def _test_no_always_callbacks(self, phrases: Iterable[str], callback: callable):
for i, phrase in enumerate(phrases):
with self.subTest(phrase):
callbacks = [registered_callback.callback for registered_callback in self.flana_tele_bot._parse_callbacks(phrase, constants.RATIO_REWARD_EXPONENT, constants.KEYWORDS_LENGHT_PENALTY, constants.MINIMUM_RATIO_TO_MATCH)
callbacks = [registered_callback.callback for registered_callback in self.flana_tele_bot._parse_callbacks(phrase, multibot_constants.RATIO_REWARD_EXPONENT, multibot_constants.KEYWORDS_LENGHT_PENALTY, multibot_constants.MINIMUM_RATIO_TO_MATCH)
if not registered_callback.always]
self.assertEqual(1, len(callbacks))
self.assertEqual(callback, callbacks[0], f'\n\nExpected: {callback.__name__}\nActual: {callbacks[0].__name__}')
@@ -111,9 +116,9 @@ class TestParseCallbacks(unittest.TestCase):
def test_on_mute(self):
phrases = [
'silencia',
'silencia al pavo ese',
'calla a ese pesao',
# 'silencia',
# 'silencia al pavo ese',
# 'calla a ese pesao',
'haz que se calle',
'quitale el microfono a ese',
'quitale el micro',
@@ -124,13 +129,6 @@ class TestParseCallbacks(unittest.TestCase):
]
self._test_no_always_callbacks(phrases, self.flana_tele_bot._on_mute)
def test_on_new_message(self):
for i in range(10):
phrase = flanautils.random_string(0, 30, n_spaces=20)
with self.subTest(phrase):
callbacks = [registered_callback.callback for registered_callback in self.flana_tele_bot._parse_callbacks(phrase)]
self.assertIn(self.flana_tele_bot._on_new_message, callbacks, f'\n\nExpected: {self.flana_tele_bot._on_new_message.__name__} in {callbacks}')
def test_on_new_message_default(self):
phrases = [
'asdqwergf',
@@ -157,7 +155,6 @@ class TestParseCallbacks(unittest.TestCase):
def test_on_punish(self):
phrases = [
'acabo con el',
'acaba con el',
'destrozalo',
'ataca',
@@ -169,8 +166,6 @@ class TestParseCallbacks(unittest.TestCase):
'castigalo',
'castiga a',
'castiga',
'banealo',
'banea',
'enseña quien manda'
]
self._test_no_always_callbacks(phrases, self.flana_tele_bot._on_punish)
@@ -249,8 +244,7 @@ class TestParseCallbacks(unittest.TestCase):
'perdona a',
'illo quitale a @flanagan el castigo',
'quita castigo',
'devuelve los permisos',
'desbanea'
'devuelve los permisos'
]
self._test_no_always_callbacks(phrases, self.flana_tele_bot._on_unpunish)
@@ -265,6 +259,8 @@ class TestParseCallbacks(unittest.TestCase):
'sol',
'temperatura',
'humedad',
'que tiempo hara mañana',
'que tiempo hara manana',
'que tiempo hace en malaga',
'que tiempo hace en calle larios',
'tiempo rusia',