Merge remote-tracking branch 'origin/main'

This commit is contained in:
Fotoente 2022-02-20 09:50:15 +01:00
commit d6763d4c6b
2 changed files with 102 additions and 107 deletions

View file

@ -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()

View file

@ -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()