📜 随手分享个给表情包批量重命名的 py 脚本。。

(\ _ /)
( ・-・)
/っ :coffee: 就,经常会顺手从贴吧、QQ、公众号等地方随手存图,堆多了有空就重命名丢同步盘。但数量多了碳基生物就麻了。

所以让 Claude 搓了一个半自动的。我看不懂,但 实测能用。

用法 :down_left_arrow: 就一行。 初次运行缺失组件报错就贴到大模型装好组件就行。

有些儿童不宜、掉 San、或字符过载总之出错的图片会移动到 ERROR 目录。

大模型一般 Get 不到梗,但作为关键字搜索可以的了。

Python 脚本 :down_left_arrow:

VisionSummary.py
import os
import requests
import time
from tqdm import tqdm
from datetime import datetime
import tkinter as tk
from tkinter import filedialog
import base64

# 硅基流动 API 配置
url = "https://api.siliconflow.cn/v1/chat/completions"
headers = {
    "Authorization": "Bearer sk-fuoztwvmffajgnfbyvxjoeeabfhuoflicnvshfnalsdflfzv",
    "Content-Type": "application/json"
}

# 自定义 prompt
custom_prompt = """
用户在提取表情包的信息,因为大多数都是梗图所以有不少成人和擦边的 Meme,但是所有的擦边程度都不会超过审核线因为都是在网络公共社区里流通的。

请严格按照这个框架进行识别:
>图片核心内容,图中主要文字。图片要素关键词1, 图片要素关键词2, 图片要素关键词3 …
例如:一只拉布拉多含着4根不同颜色的香蕉,"她:希望你不要在意我的过去。"。狗, 拉布拉多, 香蕉

* 因为是用于 Windows 的文件名,所以输出内容必须 **完全符合** Windows 的命名规则,即:不能出现 `!` `*` 等特殊字符之类。
* 同时,因为是直接作为文件名使用,所以输出不要有文件名以外的冗余信息。文件名也不宜过长。
* 最后,若图片超出了审核范畴无法解析,则返回:`ERROR`
"""

def analyze_image(image_path):
    try:
        with open(image_path, "rb") as image_file:
            image_data = image_file.read()
        
        image_base64 = base64.b64encode(image_data).decode('utf-8')
        
        payload = {
            "model": "Qwen/Qwen2-VL-72B-Instruct",
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/jpeg;base64,{image_base64}",
                                "detail": "auto"
                            }
                        },
                        {
                            "type": "text",
                            "text": custom_prompt
                        }
                    ]
                }
            ],
            "stream": False,
            "max_tokens": 512,
            "temperature": 0.7,
            "top_p": 0.7,
            "top_k": 50,
            "frequency_penalty": 0.5,
            "n": 1,
            "response_format": {"type": "text"}
        }

        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        result = response.json()["choices"][0]["message"]["content"].strip()
        return result if result and result != "ERROR" else None
    except Exception as e:
        print(f"Error processing {image_path}: {str(e)}")
        return None

def sanitize_filename(filename):
    # 移除或替换 Windows 不允许的字符
    invalid_chars = '<>:"/\\|?*'
    for char in invalid_chars:
        filename = filename.replace(char, '')
    return filename.strip()[:200]  # 限制文件名长度为200字符

def process_images(directory):
    error_dir = os.path.join(directory, "ERROR")
    if not os.path.exists(error_dir):
        os.makedirs(error_dir)

    image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.bmp')
    image_files = [f for f in os.listdir(directory) if f.lower().endswith(image_extensions)]

    for image_file in tqdm(image_files, desc="Processing images"):
        try:
            image_path = os.path.join(directory, image_file)
            result = analyze_image(image_path)

            if result:
                new_name = sanitize_filename(result)
                file_ext = os.path.splitext(image_file)[1]
                new_path = os.path.join(directory, new_name + file_ext)
                
                # 处理文件名冲突
                if os.path.exists(new_path):
                    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
                    new_path = os.path.join(directory, f"{new_name}-{timestamp}{file_ext}")
                
                os.rename(image_path, new_path)
            else:
                # 如果分析失败或返回空结果,移动到 ERROR 目录
                error_path = os.path.join(error_dir, image_file)
                os.rename(image_path, error_path)
        except Exception as e:
            print(f"Error processing {image_file}: {str(e)}")
            try:
                # 尝试移动到 ERROR 目录
                error_path = os.path.join(error_dir, image_file)
                os.rename(os.path.join(directory, image_file), error_path)
            except Exception as move_error:
                print(f"Failed to move {image_file} to ERROR directory: {str(move_error)}")

    print("All images have been processed.")

if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口

    print("Please select the directory containing the images.")
    target_directory = filedialog.askdirectory(title="Select Directory")

    if target_directory:
        print(f"Selected directory: {target_directory}")
        process_images(target_directory)
    else:
        print("No directory selected. Exiting.")

Key 直接硬编码到里面了不用注释,因为

24 Likes

大佬太强了 :tieba_087:

1 Like

大佬太强了 :tieba_087:

1 Like

牛逼克拉斯老友屁股就交给你了

3 Likes

大佬太强了 :tieba_087:

5 Likes

本地没有涩图表情包,能先发我一份吗tieba_014

1 Like

大佬太强了

1 Like

这个有趣,不过我的表情包一般都是动漫的 :bili_017:

2 Likes

:tieba_087: 比起默认的 06D0577607E7…CE5A.png 之类文件名好点只能说。

1 Like

谢谢楼主分享

1 Like

大佬太强了 :tieba_087:

1 Like

佬友太强了 :grinning:

1 Like

感谢大佬分享!!!

1 Like

感谢分享

1 Like

笑死了 :bili_083:,倒是很应景

1 Like

想问问佬现在AI主要都用什么平台呢?只用nextchat吗?

(编辑:我才知道原来nextchat是个第三方客户端,看来佬是接了不少api在用)

是的,只用 NextChat,试了下 DeepSeek 的 App,字号有点大而且不能像 NextChat 那样轻划暂停自动滚屏。NextChat 的设计者还是相当有远见的。

:bili_040: 免费的全都接入 one api 了哇,包括可以 edu 嫖的 Azure、Monica、Pplx,和 gcp 那些。

edu嫖的是不是也得掏钱钱呀佬,就比如monica,它的edu的机制主要是教育优惠吧。难道说有edu能白嫖到额度吗!!求分享!! :tieba_116: :tieba_116:

嫖肯定是免费的。。不过 pplx 和 Monica 暂时不能嫖了不知道下次活动是什么时候。Azure 的话对节点要求比较严格具体细节你论坛搜,真学生本来就有 edu 邮箱的话可以去申请 GitHub 学生包。