mirror of
https://git.squeakyrat.moe/faggot-chan/
synced 2026-11-04 18:35:45 +01:00
changed describe.py a bit
This commit is contained in:
1 parent
dc06343909
commit
a704744f5c
2 files changed
+55
-8
No files matched your search
@@ -93,7 +93,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 = 8 * 1024 * 1024 # per file we keep, stays under discord's 10mb upload limit so she can send it back
|
||||
MEDIA_SAVE_MAX_BYTES = 19 * 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:
|
||||
|
||||
+54
-7
@@ -34,6 +34,10 @@ PROMPT = ("this is a {kind} from a discord server, its name is \"{hint}\" (the n
|
||||
"the name above can help), what they're doing, and any text written in the image. "
|
||||
"don't guess when to use it, no preamble, no quotes.")
|
||||
|
||||
# only for media, the bot sends [media: name] so the file name is what she sees, a hash tells her nothing
|
||||
NAME_PROMPT = (" answer in exactly two lines. line 1: a short file name for it, 1 to 3 lowercase words joined by underscores, no extension "
|
||||
"(the character's name if you recognize them, otherwise the main subject). line 2: the description.")
|
||||
|
||||
|
||||
def model_from(script: str) -> str:
|
||||
# same trick as colab_setup.py, read the model name straight out of main.py / gemini.py so they can't drift apart
|
||||
@@ -92,7 +96,7 @@ def video_frame(path: Path, dest: Path) -> bool:
|
||||
def describe(model: str, png: Path, prompt: str) -> str:
|
||||
import ollama
|
||||
r = ollama.chat(model=model, messages=[{"role": "user", "content": prompt, "images": [str(png)]}], options={"temperature": 0.2})
|
||||
return clean(r["message"]["content"])
|
||||
return strip_think(r["message"]["content"])
|
||||
|
||||
|
||||
def describe_gemini(model: str, png: Path, prompt: str) -> str:
|
||||
@@ -109,18 +113,52 @@ def describe_gemini(model: str, png: Path, prompt: str) -> str:
|
||||
config=types.GenerateContentConfig(safety_settings=safety, temperature=0.2),
|
||||
)
|
||||
time.sleep(4) # free tier rate limit, rerun the script if some fail, it only does the empty ones
|
||||
return clean(r.text or "")
|
||||
return strip_think(r.text or "")
|
||||
|
||||
|
||||
def strip_think(text: str) -> str:
|
||||
return re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
|
||||
|
||||
|
||||
def clean(text: str) -> str:
|
||||
text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
|
||||
return " ".join(text.split()).strip(' "')
|
||||
return " ".join(strip_think(text).split()).strip(' "')
|
||||
|
||||
|
||||
def save_description(kind: str, name: str, text: str, force: bool):
|
||||
def split_name(text: str) -> tuple[str, str]:
|
||||
# media answers come back as "name\ndescription", no name (model ignored the format) = keep the file as it is
|
||||
lines = [l for l in strip_think(text).splitlines() if l.strip()]
|
||||
if len(lines) < 2:
|
||||
return "", clean(text)
|
||||
name = re.sub(r"[^a-z0-9]+", "_", lines[0].lower()).strip("_")[:40]
|
||||
return name, clean(" ".join(lines[1:]))
|
||||
|
||||
|
||||
def rename_media(old: str, name: str) -> str:
|
||||
# keeps the extension, adds _2 _3 if the name is taken. media.txt gets the new name too or the bot forgets the file on restart
|
||||
suffix = Path(old).suffix
|
||||
new = f"{name}{suffix}"
|
||||
n = 2
|
||||
while (MEDIA_DIR / new).exists() and new != old:
|
||||
new = f"{name}_{n}{suffix}"
|
||||
n += 1
|
||||
if new == old:
|
||||
return old
|
||||
(MEDIA_DIR / old).rename(MEDIA_DIR / new)
|
||||
log = MEDIA_DIR / "media.txt"
|
||||
if log.exists():
|
||||
lines = log.read_text(encoding="utf-8").splitlines()
|
||||
lines = [l[:-len(old)] + new if l.endswith(f"saved media: {old}") else l for l in lines]
|
||||
log.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
return new
|
||||
|
||||
|
||||
def save_description(kind: str, name: str, text: str, force: bool, new_name: str = None):
|
||||
# read it fresh every time, the bot adds new entries to this file while we run
|
||||
data = json.loads(REACTIONS_FILE.read_text(encoding="utf-8"))
|
||||
if name in data.get(kind, {}) and (force or not data[kind][name]):
|
||||
if new_name and new_name != name:
|
||||
data[kind][new_name] = data[kind].pop(name)
|
||||
name = new_name
|
||||
data[kind][name] = text
|
||||
REACTIONS_FILE.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
|
||||
@@ -161,14 +199,23 @@ def main():
|
||||
try:
|
||||
hint = re.sub(r"^\d+_", "", Path(name).stem) if kind == "media" else name # media is saved as id_filename
|
||||
prompt = PROMPT.format(kind=kind.rstrip("s") if kind != "media" else "media file", hint=hint)
|
||||
if kind == "media":
|
||||
prompt += NAME_PROMPT
|
||||
text = (describe_gemini if args.gemini else describe)(model, png, prompt)
|
||||
except Exception as e:
|
||||
print(f"skip {kind}/{name}: describe failed: {e}")
|
||||
continue
|
||||
new_name = None
|
||||
if kind == "media":
|
||||
new_name, text = split_name(text)
|
||||
else:
|
||||
text = clean(text)
|
||||
if not text:
|
||||
continue
|
||||
save_description(kind, name, text, args.all)
|
||||
print(f"{kind}/{name}: {text}")
|
||||
if new_name:
|
||||
new_name = rename_media(name, new_name)
|
||||
save_description(kind, name, text, args.all, new_name)
|
||||
print(f"{kind}/{name}{f' -> {new_name}' if new_name and new_name != name else ''}: {text}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user