mirror of
https://github.com/fotoente/MIsskey-ebooks-bot
synced 2024-11-25 21:00:23 +00:00
commit
95131dd374
2 changed files with 102 additions and 107 deletions
60
rdbot.py
60
rdbot.py
|
@ -1,29 +1,21 @@
|
|||
from datetime import datetime
|
||||
import os
|
||||
import asyncio
|
||||
from random import *
|
||||
import mi
|
||||
import sys
|
||||
import configparser
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from mi import Note
|
||||
|
||||
from mi.ext import commands, tasks
|
||||
from mi.note import Note
|
||||
from mi.router import Router
|
||||
from mi.framework import Note
|
||||
from mi.framework.router import Router
|
||||
|
||||
from roboduck import *
|
||||
|
||||
|
||||
|
||||
#Load Misskey configuration
|
||||
# Load Misskey configuration
|
||||
config = configparser.ConfigParser()
|
||||
config.read((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
uri="wss://"+config.get("misskey","instance_write")+"/streaming"
|
||||
token=config.get("misskey","token")
|
||||
config.read(Path(__file__).parent.joinpath('bot.cfg'))
|
||||
uri = config.get("misskey", "instance_write")
|
||||
token = config.get("misskey", "token")
|
||||
|
||||
|
||||
class MyBot(commands.Bot):
|
||||
text_model = None #Holds the markov object, so it won't be recreated everytime
|
||||
text_model = None # Holds the markov object, so it won't be recreated everytime
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
@ -35,36 +27,30 @@ class MyBot(commands.Bot):
|
|||
|
||||
@tasks.loop(43200)
|
||||
async def loop_12h(self):
|
||||
thread_update = threading.Thread(target=update)
|
||||
thread_update.setDaemon(True)
|
||||
thread_update.start()
|
||||
thread_update = threading.Thread(target=update)
|
||||
thread_update.setDaemon(True)
|
||||
thread_update.start()
|
||||
|
||||
async def on_ready(self, ws):
|
||||
await Router(ws).connect_channel(["global", "main"]) #Connect to global and main channels
|
||||
await bot.client.note.send(content=datetime.now().strftime('%Y-%m-%d %H:%M:%S') + " :roboduck: Bot started!", visibility="specified")
|
||||
self.loop_12h.start() #Launching renew posts every 12 hours
|
||||
self.loop_1h.start() #
|
||||
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S')+" Roboduck Bot started!")
|
||||
|
||||
await Router(ws).connect_channel(["global", "main"]) # Connect to global and main channels
|
||||
await bot.client.note.send(content=datetime.now().strftime('%Y-%m-%d %H:%M:%S') + " :roboduck: Bot started!",
|
||||
visibility="specified")
|
||||
self.loop_12h.start() # Launching renew posts every 12 hours
|
||||
self.loop_1h.start() #
|
||||
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S') + " Roboduck Bot started!")
|
||||
|
||||
async def on_mention(self, note: Note):
|
||||
text=""
|
||||
if (not note.author.is_bot):
|
||||
inhalt=note.content
|
||||
if (note.author.host is None):
|
||||
text = "@" + note.author.name + " " #Building the reply on same instance
|
||||
else:
|
||||
text = "@" + note.author.name + "@" + note.author.host + " " #Building the reply on foreign instance
|
||||
|
||||
if not note.author.is_bot:
|
||||
text = note.author.action.get_mention()
|
||||
text += create_sentence()
|
||||
|
||||
await note.reply(content=text) #Reply to a note
|
||||
await note.reply(content=text) # Reply to a note
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
databasepath = (Path(__file__).parent).joinpath('roboduck.db')
|
||||
databasepath = Path(__file__).parent.joinpath('roboduck.db')
|
||||
|
||||
if (not (os.path.exists(databasepath) and os.stat(databasepath).st_size != 0)):
|
||||
if not (os.path.exists(databasepath) and os.stat(databasepath).st_size != 0):
|
||||
init_bot()
|
||||
|
||||
bot = MyBot()
|
||||
|
|
149
roboduck.py
149
roboduck.py
|
@ -10,6 +10,7 @@ from pathlib import Path
|
|||
from datetime import *
|
||||
from time import sleep
|
||||
|
||||
|
||||
def check_str_to_bool(text) -> bool:
|
||||
if (text == "True" or text == "true" or text == "TRUE"):
|
||||
return True
|
||||
|
@ -18,6 +19,7 @@ def check_str_to_bool(text) -> bool:
|
|||
else:
|
||||
return True
|
||||
|
||||
|
||||
def get_notes(**kwargs):
|
||||
noteid = "k"
|
||||
sinceid = ""
|
||||
|
@ -27,12 +29,12 @@ def get_notes(**kwargs):
|
|||
|
||||
if (kwargs):
|
||||
if ("min_notes" in kwargs):
|
||||
#print("min_notes found!")
|
||||
# print("min_notes found!")
|
||||
init = True
|
||||
min_notes = kwargs["min_notes"]
|
||||
|
||||
elif ("lastnote" in kwargs):
|
||||
#print("Lastnote found!")
|
||||
# print("Lastnote found!")
|
||||
init = False
|
||||
sinceid = kwargs["lastnote"]
|
||||
|
||||
|
@ -45,41 +47,40 @@ def get_notes(**kwargs):
|
|||
print("Exiting routine")
|
||||
return None
|
||||
|
||||
#Load configuration
|
||||
# Load configuration
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__), 'bot.cfg'))
|
||||
#print(os.path.join(os.path.dirname(__file__), 'bot.cfg'))
|
||||
# print(os.path.join(os.path.dirname(__file__), 'bot.cfg'))
|
||||
|
||||
url="https://"+config.get("misskey","instance_read")+"/api/users/show"
|
||||
host=config.get("misskey","instance_read")
|
||||
url = "https://" + config.get("misskey", "instance_read") + "/api/users/show"
|
||||
host = config.get("misskey", "instance_read")
|
||||
try:
|
||||
req = requests.post(url, json={"username" : config.get("misskey","user_read"), "host" : host})
|
||||
req = requests.post(url, json={"username": config.get("misskey", "user_read"), "host": host})
|
||||
req.raise_for_status()
|
||||
except requests.exceptions.HTTPError as err:
|
||||
print("Couldn't get Username! " + str(err))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
userid = req.json()["id"]
|
||||
|
||||
#Read & Sanitize Inputs from Config File
|
||||
# Read & Sanitize Inputs from Config File
|
||||
try:
|
||||
includeReplies = check_str_to_bool(config.get("markov","includeReplies"))
|
||||
includeReplies = check_str_to_bool(config.get("markov", "includeReplies"))
|
||||
except (TypeError, ValueError) as err:
|
||||
includeReplies = True
|
||||
|
||||
try:
|
||||
includeMyRenotes = check_str_to_bool(config.get("markov","includeMyRenotes"))
|
||||
includeMyRenotes = check_str_to_bool(config.get("markov", "includeMyRenotes"))
|
||||
except (TypeError, ValueError) as err:
|
||||
includeMyRenotes = False
|
||||
|
||||
try:
|
||||
excludeNsfw = check_str_to_bool(config.get("markov","excludeNsfw"))
|
||||
excludeNsfw = check_str_to_bool(config.get("markov", "excludeNsfw"))
|
||||
except (TypeError, ValueError) as err:
|
||||
excludeNsfw = True
|
||||
|
||||
run = True
|
||||
oldnote=""
|
||||
oldnote = ""
|
||||
|
||||
while run:
|
||||
|
||||
|
@ -87,19 +88,19 @@ def get_notes(**kwargs):
|
|||
break
|
||||
|
||||
try:
|
||||
req = requests.post("https://"+config.get("misskey","instance_read")+"/api/users/notes", json = {
|
||||
"userId": userid,
|
||||
"includeReplies" : includeReplies,
|
||||
"limit" : 100,
|
||||
"includeMyRenotes" : includeMyRenotes,
|
||||
"withFiles" : False,
|
||||
"excludeNsfw" : excludeNsfw,
|
||||
"untilId" : noteid,
|
||||
"sinceId" : sinceid
|
||||
})
|
||||
req = requests.post("https://" + config.get("misskey", "instance_read") + "/api/users/notes", json={
|
||||
"userId": userid,
|
||||
"includeReplies": includeReplies,
|
||||
"limit": 100,
|
||||
"includeMyRenotes": includeMyRenotes,
|
||||
"withFiles": False,
|
||||
"excludeNsfw": excludeNsfw,
|
||||
"untilId": noteid,
|
||||
"sinceId": sinceid
|
||||
})
|
||||
req.raise_for_status()
|
||||
except requests.exceptions.HTTPError as err:
|
||||
print("Couldn't get Posts! "+str(err))
|
||||
print("Couldn't get Posts! " + str(err))
|
||||
sys.exit(1)
|
||||
|
||||
for jsonObj in req.json():
|
||||
|
@ -110,36 +111,38 @@ def get_notes(**kwargs):
|
|||
|
||||
oldnote = noteid
|
||||
|
||||
noteid = notesList[len(notesList)-1]["id"]
|
||||
noteid = notesList[len(notesList) - 1]["id"]
|
||||
|
||||
print(str(len(notesList)) + " Notes read.")
|
||||
print("Processing notes...")
|
||||
|
||||
for element in notesList:
|
||||
lastTime = element["createdAt"]
|
||||
lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z'))*1000)
|
||||
lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z')) * 1000)
|
||||
|
||||
content = element["text"]
|
||||
|
||||
if content is None: #Skips empty notes (I don't know how there could be empty notes)
|
||||
if content is None: # Skips empty notes (I don't know how there could be empty notes)
|
||||
continue
|
||||
|
||||
content = regex.sub(r"(?>@(?>[\w\-])+)(?>@(?>[\w\-\.])+)?", '', content) #Remove instance name with regular expression
|
||||
content = content.replace("::",": :") #Break long emoji chains
|
||||
content = content.replace("@", "@"+chr(8203))
|
||||
content = regex.sub(r"(?>@(?>[\w\-])+)(?>@(?>[\w\-\.])+)?", '',
|
||||
content) # Remove instance name with regular expression
|
||||
content = content.replace("::", ": :") # Break long emoji chains
|
||||
content = content.replace("@", "@" + chr(8203))
|
||||
|
||||
dict = {"id" : element["id"], "text" : content, "timestamp" : lastTimestamp}
|
||||
dict = {"id": element["id"], "text": content, "timestamp": lastTimestamp}
|
||||
returnList.append(dict)
|
||||
|
||||
return returnList
|
||||
|
||||
|
||||
def calculate_markov_chain():
|
||||
text = ""
|
||||
#Load configuration
|
||||
# Load configuration
|
||||
config = configparser.ConfigParser()
|
||||
config.read((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
try:
|
||||
max_notes = config.get("markov","max_notes")
|
||||
max_notes = config.get("markov", "max_notes")
|
||||
except (TypeError, ValueError) as err:
|
||||
max_notes = "10000"
|
||||
|
||||
|
@ -161,13 +164,14 @@ def calculate_markov_chain():
|
|||
text += row[0] + "\n"
|
||||
|
||||
markovchain = markovify.Text(text)
|
||||
markovchain.compile(inplace = True)
|
||||
markovchain.compile(inplace=True)
|
||||
|
||||
markov_json = markovchain.to_json()
|
||||
|
||||
with open((Path(__file__).parent).joinpath('markov.json'), "w", encoding="utf-8") as markov:
|
||||
json.dump(markov_json, markov)
|
||||
|
||||
|
||||
def clean_database():
|
||||
databasepath = (Path(__file__).parent).joinpath('roboduck.db')
|
||||
if (not (os.path.exists(databasepath) and os.stat(databasepath).st_size != 0)):
|
||||
|
@ -178,12 +182,12 @@ def clean_database():
|
|||
with open(databasepath, "a", encoding="utf-8") as f:
|
||||
database = sqlite3.connect(databasepath)
|
||||
|
||||
#Reading config file bot.cfg with config parser
|
||||
# Reading config file bot.cfg with config parser
|
||||
config = configparser.ConfigParser()
|
||||
config.read((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
#print((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
# print((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
try:
|
||||
max_notes = config.get("markov","max_notes")
|
||||
max_notes = config.get("markov", "max_notes")
|
||||
except (TypeError, ValueError) as err:
|
||||
max_notes = "10000"
|
||||
|
||||
|
@ -193,59 +197,60 @@ def clean_database():
|
|||
database.commit()
|
||||
database.close()
|
||||
|
||||
|
||||
def create_sentence():
|
||||
with open((os.path.join((Path(__file__).parent), 'markov.json')), "r", encoding="utf-8") as markov:
|
||||
markov_json = json.load(markov)
|
||||
|
||||
text_model = markovify.Text.from_json(markov_json)
|
||||
|
||||
note=""
|
||||
note = ""
|
||||
|
||||
#Reading config file bot.cfg with config parser
|
||||
# Reading config file bot.cfg with config parser
|
||||
config = configparser.ConfigParser()
|
||||
config.read((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
#print((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
#Read & Sanitize Inputs
|
||||
# print((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
# Read & Sanitize Inputs
|
||||
try:
|
||||
test_output = check_str_to_bool(config.get("markov","test_output"))
|
||||
test_output = check_str_to_bool(config.get("markov", "test_output"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("test_output: " + str(err))
|
||||
# print("test_output: " + str(err))
|
||||
test_output = True
|
||||
|
||||
if (test_output):
|
||||
try:
|
||||
tries = int(config.get("markov","tries"))
|
||||
tries = int(config.get("markov", "tries"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("tries: " + str(err))
|
||||
# print("tries: " + str(err))
|
||||
tries = 250
|
||||
|
||||
try:
|
||||
max_overlap_ratio = float(config.get("markov","max_overlap_ratio"))
|
||||
max_overlap_ratio = float(config.get("markov", "max_overlap_ratio"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("max_overlap_ratio: " + str(err))
|
||||
# print("max_overlap_ratio: " + str(err))
|
||||
max_overlap_ratio = 0.7
|
||||
|
||||
try:
|
||||
max_overlap_total = int(config.get("markov","max_overlap_total"))
|
||||
max_overlap_total = int(config.get("markov", "max_overlap_total"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("max_overlap_total: " + str(err))
|
||||
# print("max_overlap_total: " + str(err))
|
||||
max_overlap_total = 10
|
||||
|
||||
try:
|
||||
max_words = int(config.get("markov","max_words"))
|
||||
max_words = int(config.get("markov", "max_words"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("max_words: " + str(err))
|
||||
# print("max_words: " + str(err))
|
||||
max_words = None
|
||||
|
||||
try:
|
||||
min_words = int(config.get("markov","min_words"))
|
||||
min_words = int(config.get("markov", "min_words"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print("min_words: " + str(err))
|
||||
# print("min_words: " + str(err))
|
||||
min_words = None
|
||||
|
||||
if (max_words is not None and min_words is not None):
|
||||
if (min_words >= max_words):
|
||||
#print("min_words ("+str(min_words)+") bigger than max_words ("+str(max_words)+")! Swapping values!")
|
||||
# print("min_words ("+str(min_words)+") bigger than max_words ("+str(max_words)+")! Swapping values!")
|
||||
swap = min_words
|
||||
min_words = max_words
|
||||
max_words = swap
|
||||
|
@ -268,20 +273,21 @@ def create_sentence():
|
|||
print("min_words: " + str(min_words))
|
||||
"""
|
||||
|
||||
#Applying Inputs
|
||||
# Applying Inputs
|
||||
note = text_model.make_sentence(
|
||||
test_output = test_output,
|
||||
tries = tries,
|
||||
max_overlap_ratio = max_overlap_ratio,
|
||||
max_overlap_total = max_overlap_total,
|
||||
max_words = max_words,
|
||||
min_words = min_words
|
||||
)
|
||||
test_output=test_output,
|
||||
tries=tries,
|
||||
max_overlap_ratio=max_overlap_ratio,
|
||||
max_overlap_total=max_overlap_total,
|
||||
max_words=max_words,
|
||||
min_words=min_words
|
||||
)
|
||||
if (note is not None):
|
||||
return note
|
||||
else:
|
||||
return "Error in markov chain sentence creation: Couldn't calculate sentence!\n\n☹ Please try again! "
|
||||
|
||||
|
||||
def update():
|
||||
notesList = []
|
||||
databasepath = (Path(__file__).parent).joinpath('roboduck.db')
|
||||
|
@ -299,7 +305,7 @@ def update():
|
|||
|
||||
sinceNote = data.fetchone()[0]
|
||||
|
||||
notesList = get_notes(lastnote = sinceNote)
|
||||
notesList = get_notes(lastnote=sinceNote)
|
||||
|
||||
if (notesList == 0):
|
||||
database.close()
|
||||
|
@ -307,7 +313,8 @@ def update():
|
|||
|
||||
print("Insert new notes to database...")
|
||||
for note in notesList:
|
||||
database.execute("INSERT OR IGNORE INTO notes (id, text, timestamp) VALUES(?, ?, ?)", [note["id"], note["text"], note["timestamp"]])
|
||||
database.execute("INSERT OR IGNORE INTO notes (id, text, timestamp) VALUES(?, ?, ?)",
|
||||
[note["id"], note["text"], note["timestamp"]])
|
||||
|
||||
database.commit()
|
||||
print("Notes updated!")
|
||||
|
@ -326,6 +333,7 @@ def update():
|
|||
|
||||
print("\nUpdate done!")
|
||||
|
||||
|
||||
def init_bot():
|
||||
notesList = []
|
||||
databasepath = (Path(__file__).parent).joinpath('roboduck.db')
|
||||
|
@ -345,23 +353,24 @@ def init_bot():
|
|||
|
||||
print("Table NOTES created...")
|
||||
|
||||
#Load configuration
|
||||
# Load configuration
|
||||
config = configparser.ConfigParser()
|
||||
config.read((Path(__file__).parent).joinpath('bot.cfg'))
|
||||
try:
|
||||
initnotes = int(config.get("markov","min_notes"))
|
||||
initnotes = int(config.get("markov", "min_notes"))
|
||||
except (TypeError, ValueError) as err:
|
||||
#print(err)
|
||||
initnotes=1000
|
||||
# print(err)
|
||||
initnotes = 1000
|
||||
|
||||
print("Try reading first " + str(initnotes) + " notes.")
|
||||
|
||||
notesList = get_notes(min_notes = initnotes)
|
||||
notesList = get_notes(min_notes=initnotes)
|
||||
|
||||
print("Writing notes into database...")
|
||||
|
||||
for note in notesList:
|
||||
database.execute("INSERT INTO notes (id, text, timestamp) VALUES(?, ?, ?)", [note["id"], note["text"], note["timestamp"]])
|
||||
database.execute("INSERT INTO notes (id, text, timestamp) VALUES(?, ?, ?)",
|
||||
[note["id"], note["text"], note["timestamp"]])
|
||||
|
||||
database.commit()
|
||||
database.close()
|
||||
|
|
Loading…
Reference in a new issue