summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTianhao Wang <wth@riseup.net>2024-01-11 13:50:41 +0000
committerTianhao Wang <wth@riseup.net>2024-01-11 13:50:41 +0000
commit7b3ef7a4726ba1e76f99b8569767aea5be99a1f5 (patch)
tree5261d467e164e6542921ad35a29738d26f572123
parentebc18cf2aa3d486b744bceba1ae1479672b8bddd (diff)
interactions based on intimacy
-rw-r--r--cat.py52
-rw-r--r--catdb.py105
-rw-r--r--catquery.py25
-rw-r--r--config.py11
-rw-r--r--patterns.py2
5 files changed, 127 insertions, 68 deletions
diff --git a/cat.py b/cat.py
index 286dc0e..4415c2b 100644
--- a/cat.py
+++ b/cat.py
@@ -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)
diff --git a/catdb.py b/catdb.py
index e3bf921..2b94ee6 100644
--- a/catdb.py
+++ b/catdb.py
@@ -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;
+"""
diff --git a/config.py b/config.py
index f68e7fa..55475a0 100644
--- a/config.py
+++ b/config.py
@@ -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!"]