mirror of
https://codeberg.org/vlw/misskey-microblogger.git
synced 2025-09-13 19:03:41 +02:00
wip: 2024-11-11T15:10:14+0100 (1731334214)
This commit is contained in:
parent
dcf582d9cf
commit
439f970a31
7 changed files with 217 additions and 27 deletions
|
@ -1,24 +1,13 @@
|
||||||
{
|
{
|
||||||
"key": "API_KEY",
|
"key": "API_KEY",
|
||||||
"online": {
|
"online": {
|
||||||
"intervals": [
|
"intervals": []
|
||||||
{
|
|
||||||
"start": {
|
|
||||||
"from": 0.00,
|
|
||||||
"to": 0.00
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"from": 24.00,
|
|
||||||
"to": 24.00
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"posts": {
|
"posts": {
|
||||||
"public": {
|
"public": {
|
||||||
"percent": 0,
|
"percent": 0,
|
||||||
"cooldown": 86400
|
"cooldown": 0
|
||||||
},
|
},
|
||||||
"specified": {
|
"specified": {
|
||||||
"percent": {
|
"percent": {
|
||||||
|
@ -27,7 +16,7 @@
|
||||||
"neutral": 0,
|
"neutral": 0,
|
||||||
"enemies": 0
|
"enemies": 0
|
||||||
},
|
},
|
||||||
"cooldown": 86400
|
"cooldown": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"replies": {
|
"replies": {
|
||||||
|
|
30
generate.py
Normal file
30
generate.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import typing
|
||||||
|
|
||||||
|
from src.User.User import User
|
||||||
|
from src.Generator.GenerateUser import GenerateUser
|
||||||
|
from src.Generator.GenerateRelationships import GenerateRelationships
|
||||||
|
|
||||||
|
DEFAULT_GENERATE_USER_COUNT = 5
|
||||||
|
|
||||||
|
def generate_user() -> User:
|
||||||
|
while True:
|
||||||
|
user = GenerateUser()
|
||||||
|
print(f"1. Create username: {user.username}")
|
||||||
|
#user.set_api_key(input("2. Paste API key:"))
|
||||||
|
|
||||||
|
yield user.autorun()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
users = []
|
||||||
|
|
||||||
|
for i in (range(sys.argv[1] if len(sys.argv) > 1 else DEFAULT_GENERATE_USER_COUNT)):
|
||||||
|
print(f"\nGenerating user: {i + 1}")
|
||||||
|
users.append(next(generate_user()))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
GenerateRelationships(users).autorun()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -16,25 +16,25 @@ class DictionaryParser(Dictionary):
|
||||||
tokens = [token.lower() for token in note["text"].split(" ")]
|
tokens = [token.lower() for token in note["text"].split(" ")]
|
||||||
return set(tokens)
|
return set(tokens)
|
||||||
|
|
||||||
def get_tone(self) -> NoteTones:
|
def get_tone(self) -> NoteTones | None:
|
||||||
words = self.get_words(Dictionaries.CONTROL)["tone"]
|
words = self.get_words(Dictionaries.CONTROL)["tone"]
|
||||||
|
|
||||||
if (self.tokens & set(words[NoteTones.INFORMAL.value])): return NoteTones.INFORMAL
|
if (self.tokens & set(words[NoteTones.INFORMAL.value])): return NoteTones.INFORMAL
|
||||||
elif (self.tokens & set(words[NoteTones.FORMAL.value])): return NoteTones.FORMAL
|
elif (self.tokens & set(words[NoteTones.FORMAL.value])): return NoteTones.FORMAL
|
||||||
return NoteTones.UNKNOWN
|
return None
|
||||||
|
|
||||||
def get_mood(self) -> NoteMoods:
|
def get_mood(self) -> NoteMoods | None:
|
||||||
words = self.get_words(Dictionaries.CONTROL)["mood"]
|
words = self.get_words(Dictionaries.CONTROL)["mood"]
|
||||||
|
|
||||||
if (self.tokens & set(words[NoteMoods.FUNNY.value])): return NoteMoods.FUNNY
|
if (self.tokens & set(words[NoteMoods.FUNNY.value])): return NoteMoods.FUNNY
|
||||||
elif (self.tokens & set(words[NoteMoods.DECENT.value])): return NoteMoods.DECENT
|
elif (self.tokens & set(words[NoteMoods.DECENT.value])): return NoteMoods.DECENT
|
||||||
elif (self.tokens & set(words[NoteMoods.ANNOYED.value])): return NoteMoods.ANNOYED
|
elif (self.tokens & set(words[NoteMoods.ANNOYED.value])): return NoteMoods.ANNOYED
|
||||||
return NoteMoods.UNKNOWN
|
return None
|
||||||
|
|
||||||
def get_type(self) -> NoteTypes:
|
def get_type(self) -> NoteTypes | None:
|
||||||
words = self.get_words(Dictionaries.CONTROL)["type"]
|
words = self.get_words(Dictionaries.CONTROL)["type"]
|
||||||
|
|
||||||
if (self.tokens & set(words[NoteTypes.QUESTION.value])): return NoteTypes.QUESTION
|
if (self.tokens & set(words[NoteTypes.QUESTION.value])): return NoteTypes.QUESTION
|
||||||
elif (self.tokens & set(words[NoteTypes.EXAGGERATED.value])): return NoteTypes.EXAGGERATED
|
elif (self.tokens & set(words[NoteTypes.EXAGGERATED.value])): return NoteTypes.EXAGGERATED
|
||||||
elif (self.tokens & set(words[NoteTypes.STATEMENT.value])): return NoteTypes.STATEMENT
|
elif (self.tokens & set(words[NoteTypes.STATEMENT.value])): return NoteTypes.STATEMENT
|
||||||
return NoteTypes.UNKNOWN
|
return None
|
|
@ -1,8 +1,5 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
class Traits(Enum):
|
|
||||||
UNKNOWN = None
|
|
||||||
|
|
||||||
class Errors(Enum):
|
class Errors(Enum):
|
||||||
WORD_LIST_TOO_LONG = 0
|
WORD_LIST_TOO_LONG = 0
|
||||||
WORD_LIST_HAS_DUPLICATES = 1
|
WORD_LIST_HAS_DUPLICATES = 1
|
||||||
|
@ -43,16 +40,13 @@ class ControlWords(Enum):
|
||||||
class NoteTones(Enum):
|
class NoteTones(Enum):
|
||||||
FORMAL = "formal"
|
FORMAL = "formal"
|
||||||
INFORMAL = "informal"
|
INFORMAL = "informal"
|
||||||
UNKNOWN = Traits.UNKNOWN.value
|
|
||||||
|
|
||||||
class NoteMoods(Enum):
|
class NoteMoods(Enum):
|
||||||
FUNNY = "funny"
|
FUNNY = "funny"
|
||||||
DECENT = "decent"
|
DECENT = "decent"
|
||||||
ANNOYED = "annoyed"
|
ANNOYED = "annoyed"
|
||||||
UNKNOWN = Traits.UNKNOWN.value
|
|
||||||
|
|
||||||
class NoteTypes(Enum):
|
class NoteTypes(Enum):
|
||||||
QUESTION = "question"
|
QUESTION = "question"
|
||||||
EXAGGERATED = "exaggerated"
|
EXAGGERATED = "exaggerated"
|
||||||
STATEMENT = "statement"
|
STATEMENT = "statement"
|
||||||
UNKNOWN = Traits.UNKNOWN.value
|
|
70
src/Generator/GenerateRelationships.py
Normal file
70
src/Generator/GenerateRelationships.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import typing
|
||||||
|
import random
|
||||||
|
|
||||||
|
from ..User.User import USER_CONFIG_DIR, User
|
||||||
|
|
||||||
|
CHANCE_PARTNER = 10
|
||||||
|
|
||||||
|
RECURSE_LIMIT = 10
|
||||||
|
|
||||||
|
class GenerateRelationships():
|
||||||
|
def __init__(self, users: list = None):
|
||||||
|
self.users = users
|
||||||
|
|
||||||
|
self.partners = []
|
||||||
|
|
||||||
|
# Compute diff between a provided target list of users against list of all users
|
||||||
|
def users_diff(self, target: list) -> list:
|
||||||
|
return list(set(self.users) - set(target))
|
||||||
|
|
||||||
|
def pick_random_user_from_list(self, target: list, ignore: User) -> User:
|
||||||
|
available = self.users_diff(target)
|
||||||
|
available.remove(ignore)
|
||||||
|
|
||||||
|
return random.choice(available)
|
||||||
|
|
||||||
|
def set_random_partner(self, user: User, i: int = 0) -> None:
|
||||||
|
# Give up trying to find a partner if we've reached the recurse depth limit
|
||||||
|
if (i >= RECURSE_LIMIT):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Pick a random user
|
||||||
|
partner = self.pick_random_user_from_list(self.partners, user)
|
||||||
|
|
||||||
|
# Don't partner up with this user if they're already a friend or enemy
|
||||||
|
if (partner in user.get_enemies() or partner in user.get_friends()):
|
||||||
|
return self.set_random_partner(user, i + 1)
|
||||||
|
|
||||||
|
# Set partner's usernames in each other's configs
|
||||||
|
user.config["relationships"]["partner"] = partner.username
|
||||||
|
partner.config["relationships"]["partner"] = user.username
|
||||||
|
|
||||||
|
# Mark users as partners
|
||||||
|
self.partners.extend((user, partner))
|
||||||
|
|
||||||
|
def set_random_friend(self, user: User, i: int = 0) -> None:
|
||||||
|
# Give up trying to find a friend if we've reached the recurse depth limit
|
||||||
|
if (i >= RECURSE_LIMIT):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Get available friends (not already a friend, enemy, or self)
|
||||||
|
friend = self.pick_random_user_from_list(user.get_friends() + user.get_enemies(), user)
|
||||||
|
|
||||||
|
if (friend == user.get_partner()):
|
||||||
|
return set_random_friend(user, i + 1)
|
||||||
|
|
||||||
|
user.config["relationships"]["friends"].append(friend.username)
|
||||||
|
friend.config["relationships"]["friends"].append(user.username)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def autorun(self) -> None:
|
||||||
|
for user in self.users:
|
||||||
|
# Find a random partner for user if they don't have one already and if roll is in bounds
|
||||||
|
if (not user.get_partner()):
|
||||||
|
self.set_random_partner(user)
|
||||||
|
|
||||||
|
self.set_random_friend(user)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
107
src/Generator/GenerateUser.py
Normal file
107
src/Generator/GenerateUser.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import math
|
||||||
|
import json
|
||||||
|
import typing
|
||||||
|
import random
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ..User.User import USER_CONFIG_DIR, User
|
||||||
|
from ..Enums import RelationshipType, NoteTones, NoteMoods, NoteTypes
|
||||||
|
|
||||||
|
from misskey.enum import NoteVisibility
|
||||||
|
from random_username.generate import generate_username
|
||||||
|
|
||||||
|
# Use this file as a template for generated users
|
||||||
|
USER_TEMPLATE_FILE = Path.cwd() / "data" / "users_template.json"
|
||||||
|
|
||||||
|
# Minimum and maximum cooldown time for posting new notes
|
||||||
|
CONFIG_POST_MIN_COOLDOWN = 300 # 10 minutes
|
||||||
|
CONFIG_POST_MAX_COOLDOWN = 259200 # 48 hours
|
||||||
|
|
||||||
|
# Available preferred reactions
|
||||||
|
REACTIONS = [
|
||||||
|
"❤",
|
||||||
|
"👍",
|
||||||
|
"😆"
|
||||||
|
]
|
||||||
|
|
||||||
|
class GenerateUser():
|
||||||
|
def __init__(self):
|
||||||
|
self.username = self.gen_username()
|
||||||
|
|
||||||
|
# Load user template file
|
||||||
|
with open(USER_TEMPLATE_FILE, "r") as f:
|
||||||
|
self.config = json.load(f)
|
||||||
|
|
||||||
|
# Return a random unique username
|
||||||
|
@staticmethod
|
||||||
|
def gen_username() -> str:
|
||||||
|
username = generate_username(1)[0]
|
||||||
|
return username if not (USER_CONFIG_DIR / f"{username}.json").exists() else GenerateUser.gen_username()
|
||||||
|
|
||||||
|
# Generate a random time interval
|
||||||
|
@staticmethod
|
||||||
|
def gen_interval() -> dict:
|
||||||
|
def to_time(h: int) -> float:
|
||||||
|
return float(f"{h}.{random.randint(0, 59)}")
|
||||||
|
|
||||||
|
start_hour_from = random.randint(0, 22)
|
||||||
|
start_hour_end = start_hour_from + 1
|
||||||
|
|
||||||
|
end_hour_from = random.randint(min(start_hour_end + 1, 22), 23)
|
||||||
|
end_hour_to = min(end_hour_from + 1, 23)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"start": {
|
||||||
|
"from": to_time(start_hour_from),
|
||||||
|
"to": to_time(start_hour_end)
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"from": to_time(end_hour_from),
|
||||||
|
"to": to_time(end_hour_to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_api_key(self, key: str) -> None:
|
||||||
|
self.config["key"] = key
|
||||||
|
|
||||||
|
def save(self) -> bool:
|
||||||
|
USER_CONFIG_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
with open(USER_CONFIG_DIR / f"{self.username}.json", "w") as f:
|
||||||
|
json.dump(self.config, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
def autorun(self) -> User:
|
||||||
|
# Generate a random online interval
|
||||||
|
self.config["online"]["intervals"].append(self.gen_interval())
|
||||||
|
|
||||||
|
# Set a random percent for user to post new notes
|
||||||
|
self.config["actions"]["posts"]["public"]["percent"] = random.randint(0, 100)
|
||||||
|
self.config["actions"]["posts"]["public"]["cooldown"] = random.randint(CONFIG_POST_MIN_COOLDOWN, CONFIG_POST_MAX_COOLDOWN)
|
||||||
|
|
||||||
|
# Set random reply chance for each relationship
|
||||||
|
for visiblity in [NoteVisibility.PUBLIC, NoteVisibility.SPECIFIED]:
|
||||||
|
for relationship in RelationshipType:
|
||||||
|
self.config["actions"]["replies"][visiblity.value]["percent"][relationship.value] = random.randint(0, 100)
|
||||||
|
|
||||||
|
# Set random react chances for each relationship
|
||||||
|
for relationship in RelationshipType:
|
||||||
|
self.config["actions"]["reacts"]["percent"][relationship.value] = random.randint(0, 100)
|
||||||
|
|
||||||
|
# Set preferred reactions for each relationship
|
||||||
|
for relationship in RelationshipType:
|
||||||
|
self.config["actions"]["reacts"]["prefrerred_reaction"][relationship.value] = random.choice(REACTIONS)
|
||||||
|
|
||||||
|
# Set random personality tone
|
||||||
|
for x in NoteTones:
|
||||||
|
self.config["personality"]["tone"]["probability"][x.value] = random.randint(0, 100)
|
||||||
|
|
||||||
|
# Set random personality mood
|
||||||
|
for x in NoteMoods:
|
||||||
|
self.config["personality"]["mood"]["probability"][x.value] = random.randint(0, 100)
|
||||||
|
|
||||||
|
# Set random personality type
|
||||||
|
for x in NoteTypes:
|
||||||
|
self.config["personality"]["type"]["probability"][x.value] = random.randint(0, 100)
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
return User(self.username)
|
0
src/Generator/__init__.py
Normal file
0
src/Generator/__init__.py
Normal file
Loading…
Add table
Reference in a new issue