This commit is contained in:
dece 2023-08-24 00:26:04 +02:00
parent c6326d5ee0
commit e6c3edcdbd
4 changed files with 602 additions and 362 deletions

View file

@ -19,3 +19,4 @@ scaruffi = "==0.0.3"
wolframalpha = "*" wolframalpha = "*"
meteofrance-api = "~=1.0.2" meteofrance-api = "~=1.0.2"
openai = "~=0.25.0" openai = "~=0.25.0"
apscheduler = "~=3.9.0"

917
Pipfile.lock generated

File diff suppressed because it is too large Load diff

View file

@ -69,7 +69,7 @@
"commands": ["doupsland"] "commands": ["doupsland"]
}, },
"gpt3": { "gpt3": {
"openai_key": "" "openai_key": "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",
"join_lines": "; ", "join_lines": "; ",
"computing_replies": ["Hmm…"] "computing_replies": ["Hmm…"]
}, },
@ -176,6 +176,11 @@
"wakeup_messages": ["/me wakes up"], "wakeup_messages": ["/me wakes up"],
"snore_rate": 1.0 "snore_rate": 1.0
}, },
"shrlok": {
"socket_path": "/tmp/shrlok.sock",
"file_root": "/tmp",
"url_root": "http://localhost/"
},
"taxref": { "taxref": {
"commands": ["taxref", "scientifize"], "commands": ["taxref", "scientifize"],
"not_found_reply": "Not found!", "not_found_reply": "Not found!",
@ -203,7 +208,7 @@
"aliases": { "aliases": {
"wolfram": ["wolframalpha", "compute"] "wolfram": ["wolframalpha", "compute"]
}, },
"api_key": "", "api_key": "URTWTW-3KHWL4VV8W",
"max_pods": 1 "max_pods": 1
}, },
"yell": { "yell": {
@ -213,7 +218,7 @@
}, },
"youtube": { "youtube": {
"commands": ["youtube"], "commands": ["youtube"],
"api_key": "" "api_key": "AIzaSyCSyKdjGxcfjcj7FmgQRlWXF7ARpX8TC80"
} }
} }
} }

View file

@ -1,3 +1,4 @@
import asyncio
import importlib import importlib
import json import json
import os import os
@ -9,13 +10,15 @@ from pathlib import Path
from typing import Any, Iterable, Optional from typing import Any, Iterable, Optional
import irc.client import irc.client
import irc.client_aio
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from irc.client import Connection, Event, NickMask from irc.client import Connection, Event, NickMask
from edmond.log import Logger from edmond.log import Logger
from edmond.plugin import Plugin from edmond.plugin import Plugin
class Bot(irc.client.SimpleIRCClient, Logger): class Bot(irc.client_aio.AioSimpleIRCClient, Logger):
"""Main class for the IRC bot: handles connection and manages plugins.""" """Main class for the IRC bot: handles connection and manages plugins."""
CHANNELS_RUNTIME_KEY = "_channels" CHANNELS_RUNTIME_KEY = "_channels"
@ -27,7 +30,9 @@ class Bot(irc.client.SimpleIRCClient, Logger):
self.plugins: list[Plugin] = [] self.plugins: list[Plugin] = []
self.values: dict[str, Any] = {} self.values: dict[str, Any] = {}
self.storage: dict[str, Any] = self.get_storage() self.storage: dict[str, Any] = self.get_storage()
self.tasks: list[asyncio.Task] = []
self.done: bool = False self.done: bool = False
self.scheduler = AsyncIOScheduler()
@property @property
def nick(self) -> str: def nick(self) -> str:
@ -72,6 +77,11 @@ class Bot(irc.client.SimpleIRCClient, Logger):
except OSError as exc: except OSError as exc:
self.log_e(f"Could not save storage file: {exc}") self.log_e(f"Could not save storage file: {exc}")
def handle_task(self, coro):
"""Schedule a task in the event loop. Keep a reference to cancel it."""
task = self.connection.reactor.loop.create_task(coro)
self.tasks.append(task)
def on_welcome(self, connection: Connection, event: Event): def on_welcome(self, connection: Connection, event: Event):
"""Handle a successful connection to a server.""" """Handle a successful connection to a server."""
self.log_i(f"Connected to server {event.source}.") self.log_i(f"Connected to server {event.source}.")
@ -84,8 +94,14 @@ class Bot(irc.client.SimpleIRCClient, Logger):
if event.source.nick == self.nick: if event.source.nick == self.nick:
self.log_i(f"Joined {event.target}.") self.log_i(f"Joined {event.target}.")
self.channels.append(event.target) self.channels.append(event.target)
self.scheduler.add_job(self.flubiz, 'cron', hour='1',
minute='52')
self.scheduler.start()
self.run_plugin_callbacks(event) self.run_plugin_callbacks(event)
async def flubiz(self):
self.say('#idi0crates', "acab")
def on_part(self, connection: Connection, event: Event): def on_part(self, connection: Connection, event: Event):
"""Handle someone, possibly the bot, leaving a channel.""" """Handle someone, possibly the bot, leaving a channel."""
if event.source.nick == self.nick: if event.source.nick == self.nick:
@ -118,11 +134,14 @@ class Bot(irc.client.SimpleIRCClient, Logger):
"""Connect the bot to server, join channels and start responding.""" """Connect the bot to server, join channels and start responding."""
self.log_i("Starting Edmond.") self.log_i("Starting Edmond.")
self.load_plugins() self.load_plugins()
self.log_i("Connecting to server.") self.log_i("Connecting to server")
self.connect(self.config["host"], self.config["port"], self.nick)
signal.signal(signal.SIGTERM, self.handle_sigterm) signal.signal(signal.SIGTERM, self.handle_sigterm)
try: try:
self.connect(self.config["host"], self.config["port"], self.nick)
self.start() self.start()
except irc.client.ServerConnectionError as exc:
self.log_c(f"Connection failed: {exc}")
except KeyboardInterrupt: except KeyboardInterrupt:
self.log_i("Caught keyboard interrupt.") self.log_i("Caught keyboard interrupt.")
except Exception as exc: except Exception as exc:
@ -135,7 +154,7 @@ class Bot(irc.client.SimpleIRCClient, Logger):
def load_plugins(self): def load_plugins(self):
"""Load all installed plugins.""" """Load all installed plugins."""
self.log_i("Loading plugins.") self.log_i("Loading plugins")
plugin_files = os.listdir(Path(__file__).parent / "plugins") plugin_files = os.listdir(Path(__file__).parent / "plugins")
plugin_names = map( plugin_names = map(
lambda f: os.path.splitext(f)[0], lambda f: os.path.splitext(f)[0],
@ -199,7 +218,13 @@ class Bot(irc.client.SimpleIRCClient, Logger):
if self.done: if self.done:
return return
self.log_i("Stopping Edmond.") self.log_i("Stopping Edmond.")
self.save_storage() self.save_storage() # FIRST THINGS FIRST
for task in self.tasks:
if not task.cancelled():
self.log_d(f"Cancelling task {task.get_name()}")
task.cancel()
if self.connection.is_connected(): if self.connection.is_connected():
self.connection.close() self.connection.close()
self.reactor.loop.close()
self.done = True self.done = True