aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bot.py37
1 files changed, 22 insertions, 15 deletions
diff --git a/bot.py b/bot.py
index 8fa19b1..3b56a00 100644
--- a/bot.py
+++ b/bot.py
@@ -34,6 +34,7 @@ DM_DIR = LOG_DIR / "dm" # one memory file per person so dms never end
ERROR_FILE = LOG_DIR / "errorlog.txt"
MEMORY_FILE = LOG_DIR / "memory.txt"
+MEDIA_FILE = MEDIA_DIR / "media.txt"
THREADS_FILE = CONFIG_DIR / "threads.txt"
PROMPT_FILE = CONFIG_DIR / "system_prompt.txt"
BLOCKED_FILE = CONFIG_DIR / "blocked.txt" # edited with admin.py, re-read on every message
@@ -45,7 +46,7 @@ DEFAULT_SETTINGS = {"admin_id": "1000000000000001", "moralfag_id": "100000000000
def init_files():
for d in (LOG_DIR, MEDIA_DIR, CONFIG_DIR, DM_DIR):
d.mkdir(parents=True, exist_ok=True)
- for f in (ERROR_FILE, MEMORY_FILE):
+ for f in (ERROR_FILE, MEMORY_FILE, MEDIA_FILE):
f.touch(exist_ok=True)
if not THREADS_FILE.exists():
THREADS_FILE.write_text("6\n")
@@ -91,7 +92,7 @@ QUIET_COOLDOWN = 600 # seconds of silence before she's allowed to send a random
MEDIA_MIMES = ("image/png", "image/jpeg", "image/webp", "image/heic", "image/heif",
"audio/", "video/", "application/pdf", "text/plain") # what gemini can actually read
MEDIA_MAX_BYTES = 10 * 1024 * 1024 # total per message, gemini caps inline request size (~20mb and base64 adds a third)
-MEDIA_SAVE_MAX_BYTES = 19 * 1024 * 1024 # per file we keep and offer, has to fit the server's upload limit or she can't send it back
+MEDIA_SAVE_MAX_BYTES = 8 * 1024 * 1024 # per file we keep, stays under discord's 10mb upload limit so she can send it back
def log_error(text: str):
with ERROR_FILE.open("a", encoding="utf-8") as f:
@@ -196,12 +197,17 @@ async def call_main(payload: str) -> tuple[bool, str]:
async with _main_lock:
if not (FALLBACK_URI and time.time() < quota_until): # skip gemini while it's known to be out of quota
ok, result, quota = await call_backend(MAIN_URI, payload)
- if not quota:
+ if ok:
return ok, result
- quota_until = time.time() + QUOTA_COOLDOWN
- if not FALLBACK_URI:
- return False, QUOTA_MSG
- print(f"[{now_str()}] gemini is out of quota, using the fallback for the next {QUOTA_COOLDOWN // 60} min")
+ if quota:
+ quota_until = time.time() + QUOTA_COOLDOWN
+ if not FALLBACK_URI:
+ return False, QUOTA_MSG
+ print(f"[{now_str()}] gemini is out of quota, using the fallback for the next {QUOTA_COOLDOWN // 60} min")
+ elif not FALLBACK_URI:
+ return False, result
+ else:
+ print(f"[{now_str()}] main backend failed ({result}), trying the fallback") # dead server / 502 / any other error
ok, result, _ = await call_backend(FALLBACK_URI, payload)
return ok, result
@@ -251,13 +257,14 @@ async def send_reply(message, text: str):
vector_db_ready = False # gets set to True after first rebuild so we don't keep rebuilding
-MEDIA_EXTS = (".gif", ".png", ".jpg", ".jpeg", ".webp", ".mp4", ".webm", ".mov", ".mkv")
-
-def scan_media() -> set:
- # whatever is in the media folder is what she can send, skips media.txt and anything too big to upload
- return {p.name for p in MEDIA_DIR.iterdir() if p.is_file() and p.suffix.lower() in MEDIA_EXTS and p.stat().st_size <= MEDIA_SAVE_MAX_BYTES}
+saved_media = set() # file names inside MEDIA_DIR
-saved_media = scan_media() # file names inside MEDIA_DIR
+with MEDIA_FILE.open("r", encoding="utf-8") as f:
+ for line in f:
+ if "saved media:" in line:
+ name = line.split("saved media:", 1)[1].strip()
+ if (MEDIA_DIR / name).is_file(): # old entries were urls (those expire), they don't match a file so they get dropped
+ saved_media.add(name)
async def steal_media(url: str, name: str):
# discord cdn links are signed and die after a day or so, so we keep our own copy
@@ -281,6 +288,8 @@ async def steal_media(url: str, name: str):
saved_media.discard(name)
log_error(f"[{now_str()}] failed to save media {url}: {e}")
return
+ with MEDIA_FILE.open("a", encoding="utf-8") as f:
+ f.write(f"[{now_str()}] saved media: {name}\n")
async def steal_attachments(message):
#steal images and gifs and stuff (always do this regardless of what else fires)
@@ -429,8 +438,6 @@ def sync_reactions(guild):
def reaction_tool_prompt(guild) -> str:
# the "tool": instead of (or along with) words she can write a [sticker: name] / [emoji: name] / [media: name] tag and
# split_reactions picks it back out of the reply. same call as the reply, so no extra latency or gemini quota.
- saved_media.clear() # ls the folder again so files added / renamed (describe.py) while she's running show up
- saved_media.update(scan_media())
sync_reactions(guild)
data = load_reactions()
have = {