diff options
| -rw-r--r-- | cat.py | 52 | ||||
| -rw-r--r-- | catdb.py | 105 | ||||
| -rw-r--r-- | catquery.py | 25 | ||||
| -rw-r--r-- | config.py | 11 | ||||
| -rw-r--r-- | patterns.py | 2 |
5 files changed, 127 insertions, 68 deletions
@@ -71,7 +71,7 @@ class VnilCat: exit() self.intimacy = {} print("[booting] init intimacy") - self.update_intimacy() + self.sync_db_intimacy() # try to fetch the lastest status from the timeline # so that we can skip the ones before we start. @@ -88,8 +88,9 @@ class VnilCat: print(f"[booting] Cat booted, all systems green, my name is {self.config.UNAME}, prepare to die, human") print("-------------") - def update_intimacy(self): - res = self.db.count_interaction() + def sync_db_intimacy(self): + # res = self.db.count_interaction() + res = self.db.get_intimacy() if res != None: self.intimacy = res @@ -104,7 +105,7 @@ class VnilCat: content=random.choice(cat_sounds) + " " + emojis.random_meowcode() self.session.status_reply( to_status=ori_status, status=content) - self.db.insert_event(_type="meow",remarks="",correspond=ori_status["account"]["acct"]) + # self.db.insert_event(_type="meow",remarks="",correspond=ori_status["account"]["acct"]) def post_hn_news(self, amount=3): print("posting news") @@ -125,13 +126,17 @@ class VnilCat: self.session.toot(status) + def meowaction(self, status): + self.session.post_emoji_react_by_id(status['id'], emojis.random_meowcode()) + def catch_birds(self, status, content): if re_contains_bird.search(content) is not None and len(content) < self.config.CATCH_BIRD_MAX_LENGTH: print("i see a bird", status["id"], " from ", status["account"]["acct"]) try: s = self.session.status_reply( to_status=status, status=random.choice(bird_sounds)) - self.db.insert_event(_type="bird",remarks="",correspond=status["account"]["acct"]) + # self.db.insert_event(_type="bird",remarks="",correspond=status["account"]["acct"]) + self.db.update_intimacy(ori_status["account"]["acct"]) return True except: print("fail to post") @@ -141,7 +146,10 @@ class VnilCat: if re_contains_meow.search(content) is not None and len(content) < self.config.CATCH_CAT_MAX_LENGTH: print("i see a cat", status["id"], " from ", status["account"]["acct"]) try: - self.reply_meow(status) + if bool(random.getrandbits(1)): + self.reply_meow(status) + else: + self.meowaction(status) return True except: print("fail to post") @@ -168,13 +176,27 @@ class VnilCat: if self.is_mine(status): print("this one is from myself, skipping") return - acc = status["account"] content = cleanhtml(status["content"]) # only one action is taken. if one succeed then return if self.catch_birds(status,content): return elif self.catch_cats(status,content): return + self.like_a_cat(status) + # do we have enough intimacy? + + def like_a_cat(self,status): + acct = status["account"]["acct"] + if acct not in self.intimacy.keys(): + return + if self.intimacy[acct] > 42 and self.decision(0.2): + try: + self.meowaction(status) + except: + return + + def decision(self, probability): + return random.random() < probability def scantimeline(self): # print("scanning timeline, lastseen=",self.tl_lastseen_sid) @@ -219,7 +241,8 @@ class VnilCat: nid = notification["id"] acct = notification['account']['acct'] print(f"{acct} is petting me! purrr") - self.db.insert_event(_type="fav", remarks="",correspond=acct) + # self.db.insert_event(_type="fav", remarks="",correspond=acct) + self.db.update_intimacy(acct) self.session.notifications_dismiss(nid) def handle_notification(self): @@ -238,11 +261,16 @@ class VnilCat: while True: try: self.handle_notification() - self.scantimeline() - if self.epoch % 360 == 1 : - # happens roughtly every 2 hours + if self.epoch % 2 == 1: + # 2x EPOCH = 40s + self.scantimeline() + if self.epoch % 360 == 1: + # 360x EPOCH = 7200s/2hr + self.sync_db_intimacy() + if self.epoch % 720 == 1 : + # 4hr self.post_hn_news(3) - self.update_intimacy() + except Exception as e: print("something wrong...") print(e) @@ -3,53 +3,66 @@ from catquery import * import sqlite3 class DBHandler(): - def __init__(self,config): - self.DB = cfg.DB_NAME - self.init_db() - return - - def init_db(self): - self.commit(DB_SCHEMA) - - # this wrapper doesn't handle exception - # catch them in the caller. - # another remark: we don't expect much DB throughput - # and it's not necessary to maintain a long-lived connection - def commit(self, str, data=None): - conn = sqlite3.connect(self.DB) - cur = conn.cursor() - if data == None: - cur.execute(str) - else: - cur.execute(str,data) - conn.commit() - conn.close() - - # read-only access - def query(self,str): - conn = sqlite3.connect(self.DB) - cur = conn.cursor() - res = cur.execute(str).fetchall() - conn.close() - return res - - # the insert_event exception should be handled here - # because this is used as a log, and should have no effect - # on the programs even if it fails - def insert_event(self, _type, remarks, correspond): - try: - self.commit(QUERY_INSERT_EVENT, (_type,remarks,correspond)) - except Exception as e: - print("ERROR ","failed to insert event to the db, ignoring ",e) - - def count_interaction(self): - try: - res = self.query(QUERY_COUNT_INTERACTION) - return dict(res) - except: - print("query failed") - return None + def __init__(self,config): + self.DB = cfg.DB_NAME + self.init_db() + return + def init_db(self): + # self.commit(DB_SCHEMA) + self.commit(DB_SCHEMA_INT) + # this wrapper doesn't handle exception + # catch them in the caller. + # another remark: we don't expect much DB throughput + # and it's not necessary to maintain a long-lived connection + def commit(self, str, data=None): + conn = sqlite3.connect(self.DB) + cur = conn.cursor() + if data == None: + cur.execute(str) + else: + cur.execute(str,data) + conn.commit() + conn.close() + + # read-only access + def query(self,str): + conn = sqlite3.connect(self.DB) + cur = conn.cursor() + res = cur.execute(str).fetchall() + conn.close() + return res + + # the insert_event exception should be handled here + # because this is used as a log, and should have no effect + # on the programs even if it fails + def insert_event(self, _type, remarks, correspond): + try: + self.commit(QUERY_INSERT_EVENT, (_type,remarks,correspond)) + except Exception as e: + print("ERROR ","failed to insert event to the db, ignoring ",e) + + def count_interaction(self): + try: + res = self.query(QUERY_COUNT_INTERACTION) + return dict(res) + except: + print("query failed") + return None + + def get_intimacy(self): + try: + res = self.query(QUERY_GET_INT) + return dict(res) + except: + print("query failed") + return None + + def update_intimacy(self, name): + try: + self.commit(QUERY_UPDATE_INT,(name,name)) + except Exception as e: + print("ERROR", "failed to update intimacy ",e) diff --git a/catquery.py b/catquery.py index 12921c4..10d5b37 100644 --- a/catquery.py +++ b/catquery.py @@ -21,3 +21,28 @@ SELECT correspond, count(correspond) FROM events GROUP by correspond """ + + +DB_SCHEMA_INT = \ +""" +CREATE TABLE IF NOT EXISTS + intimacy( + correspond TEXT PRIMARY KEY, + score INTEGER + ) + +""" + +QUERY_UPDATE_INT = \ +""" +INSERT INTO intimacy(correspond,score) + VALUES(?1, 0) + ON CONFLICT(correspond) DO UPDATE SET + score=score+1 + WHERE correspond=?2 +""" + +QUERY_GET_INT = \ +""" +SELECT correspond, score FROM intimacy; +""" @@ -34,14 +34,7 @@ INTIMACY_ACTIVE = 50 INTIMACY_LOVE = 100 # BEHAVIOURS .. -CATCH_BIRD_MAX_LENGTH = 20 -CATCH_CAT_MAX_LENGTH = 20 - -## DB CONFIGS ----------------------------- -# TODO, currently the bot and the db handler is sharing -# the same set of config, which is not deserable, expecially -# when the bot config has embeded script (the try..except block -# above). For the prototyle I'm keeping it this way. May change -# later. +CATCH_BIRD_MAX_LENGTH = 48 +CATCH_CAT_MAX_LENGTH = 48 DB_NAME = "data/data.db" diff --git a/patterns.py b/patterns.py index 2bf400d..d5a99ce 100644 --- a/patterns.py +++ b/patterns.py @@ -2,7 +2,7 @@ import re #### RE PATTERNS #### re_contains_meow = re.compile(r'(me+o+w|喵|にゃん|nya+n)',re.IGNORECASE) -re_contains_bird = re.compile(r'(鸟|bird|鳥)',re.IGNORECASE) +re_contains_bird = re.compile(r'(鸟|鳥)',re.IGNORECASE) #### MISC STRING PRESETS #### cat_sounds = ["Meow!", "Mrrrow!", "Purr...", "Meee-OW!", "Mreoww!", "Nya~", "Mew?", "Rowr?", "Prrrr...", "Maow-maow!"] bird_sounds = ["鸟!", "chirp!"] |
