diff options
| author | david <[email protected]> | 2026-10-30 20:52:44 -0300 |
|---|---|---|
| committer | david <[email protected]> | 2026-10-30 20:52:44 -0300 |
| commit | 81687ccb81c1aa1827ccd860fac1247cafe343b0 (patch) | |
| tree | 2d4d808fdf47ba7c453c5979c99878d893bb2220 | |
| parent | 00930d9d75a7dd7d4839b43379d1ef27e08d77b9 (diff) | |
| download | faggot-chan-master.tar.gz faggot-chan-master.zip | |
| -rw-r--r-- | bot.py | 37 |
1 files changed, 22 insertions, 15 deletions
@@ -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 = { |
