From dac41786ececf6e2d181098e575147a309fcb885 Mon Sep 17 00:00:00 2001 From: ljh938527 <2689819155@qq.com> Date: Sun, 7 Dec 2025 14:31:28 +0800 Subject: [PATCH] first commit --- config.toml | 11 +++ controllers/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 155 bytes .../compress_image.cpython-313.pyc | Bin 0 -> 2308 bytes .../localfile_handles.cpython-313.pyc | Bin 0 -> 1444 bytes controllers/compress_image.py | 52 +++++++++++ controllers/localfile_handles.py | 14 +++ controllers/logs/2025-12-07.log | 0 main.py | 17 ++++ models/__init__.py | 0 models/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 150 bytes models/__pycache__/connect_db.cpython-313.pyc | Bin 0 -> 3706 bytes models/__pycache__/emoji_db.cpython-313.pyc | Bin 0 -> 2816 bytes models/__pycache__/generator.cpython-313.pyc | Bin 0 -> 2457 bytes models/__pycache__/logger.cpython-313.pyc | Bin 0 -> 2151 bytes models/connect_db.py | 88 ++++++++++++++++++ models/emoji_db.py | 73 +++++++++++++++ models/generator.py | 44 +++++++++ models/logger.py | 61 ++++++++++++ models/logs/2025-12-07.log | 2 + test.py | 36 +++++++ 21 files changed, 398 insertions(+) create mode 100644 config.toml create mode 100644 controllers/__init__.py create mode 100644 controllers/__pycache__/__init__.cpython-313.pyc create mode 100644 controllers/__pycache__/compress_image.cpython-313.pyc create mode 100644 controllers/__pycache__/localfile_handles.cpython-313.pyc create mode 100644 controllers/compress_image.py create mode 100644 controllers/localfile_handles.py create mode 100644 controllers/logs/2025-12-07.log create mode 100644 main.py create mode 100644 models/__init__.py create mode 100644 models/__pycache__/__init__.cpython-313.pyc create mode 100644 models/__pycache__/connect_db.cpython-313.pyc create mode 100644 models/__pycache__/emoji_db.cpython-313.pyc create mode 100644 models/__pycache__/generator.cpython-313.pyc create mode 100644 models/__pycache__/logger.cpython-313.pyc create mode 100644 models/connect_db.py create mode 100644 models/emoji_db.py create mode 100644 models/generator.py create mode 100644 models/logger.py create mode 100644 models/logs/2025-12-07.log create mode 100644 test.py diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..6fddf41 --- /dev/null +++ b/config.toml @@ -0,0 +1,11 @@ +safe_entry = "mcunc" +tokenTTL = 3600 # token有效期 单位:s +cacheTTL = 300 # token过期缓存,单位:s + +# 数据库配置 +#db_host = "sz.mcunc.site" +db_host = "localhost" +db_port = 3306 +db_user = "root" +db_password = "ljh20080924" +db_database = "emoji" \ No newline at end of file diff --git a/controllers/__init__.py b/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controllers/__pycache__/__init__.cpython-313.pyc b/controllers/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bc6fdee0033d9be8c2e3858b17e104d844949ab GIT binary patch literal 155 zcmey&%ge<81aCb|GC}lX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~iAi&acOWl2VU zUQBLsXoow4-%PchztjNyieKcR$}ua=h#3YfU==n1F;&_Whm=ssV4koM zhe${=pp)DPYI9qliltbxQ_ZS6)jLU6T@HH5UInDw3NxL?I&Ef!q-ycG+#F(b0w)Fo zPOsnX=Afka2gN{8boThY-RM;fkr47-WX?1uGAZChk{kG z%H7D{HJWSf<&^DIewWNSK&>LnvqX&+0G@n~jRJXRp5|@vs^{!RCp-9R_*7y-?=z6yftEMxJs|c2iy^b1c0Fv92Nj zki0}*%~Q5OMk!-qeO@AS4mGPmS-&MLs_dD=m<2J0v2tjNFdTM7Pe z&yiml&sih>$teG)ic-rFXDiB~v?9b^DD(e}%8~bL5T0w0L0Nwrqf;(pXn$Ge@{}!f z00Ur)b`bJu3~-w^fNHQMr__z=x(D5f3c#RW8@HFJ06hwGagad*O=|MP)TLXC;ZW+r z`Nf-;Q-hNWAB9p^FQ&%6NKHl_-5i{s9=A2jPu)lj4bOi!^yp?-qd5TGf>pzy;orMRY+oCp!C%S((L4 zR~JS@vN-2LdOE&zb!_{#ZMFt{K0f$F(B<`rr<{Vw1+2`%waCJkpDo?KGC%$K{M41D z>l5ivB!&KyvBisL7p{z_hi{`$vUX}SG1xQRCKm>i3qE=QsXrCLVbr#0uHPewPJf>V zpk^W|ENKKBfcR3LCM~@Iw^=EX_NImdlA>KA5F?R?+7C9Rok#(RXn#QT_&ldMiOPAM zb|6U_H{`Y;ZbjJ>nIOKtvMXa>EnOeqAOW*cQu+mn_PP4FZVwbB5~D3q2rvQLq>s4- zj(7PuiR|@zc+^IP073@hwkeVR0LM$D&)@AC5}IVeh`;5x}kgdn1xn`^}?4njXP z7f70XLLu%oQo)nlNV>I{OS&G9mvdqlP~M~h?1eMqhBlY*jGKhV=Z2`800Fm4oVd)8 z_P=HAY(FI)_w${;t{~sldC=$Y^&IB<#U_sDpiA__PUNo${a!Bz1;qOTkP`%_2Y*T| zfm4#<=_R-o*~eH4PL!Mhu=)~EQ6bxVwy1uB{E@6#RfBbRKzG3tIHlPF|H%aeuG11)o=bt9W&n@6f+)$ud;E&CFdeN)1n14&Ecof8R5 z%iYF=#hx^=1Ga}$agt)@4aJe(bG`BMq@ik%nAI90yTZGoXOh~gSyRc#*4WlKmo!xk zzBx;4BXpRKz8LSB5U1>ebb{VLXEa6kB#jj_bj7k77>fp)9%_oB4d<)p^rpzsb4TNv zd-}>zVb*Ah^oRT7dy~d3v!!JteX+jLSCge%qQtDu7-|G0P42w2ey};AYk5oo zL)EGd=nRp%a9yN6Tp!<))NY=rN@y*UWl61duDCS%PO`XiMpyZeHYVtbL29`KXid?E zq3YEafJz%`eYZ7Q7q`Z%NBNne+I!^dvs(S*GGz8AedV8m4gvi=v9qz1_@PwOSVfr$ zsYuQT*PTt0kiLtw(zuGuG{oN$iD++W%@(E}m!wy)Wa|&&Z#3M1Ck9VAmzTi`ngM(b zO%nYE(hqvMeQ*bQ#kWr|qiLB?C=@?~f(M}F0oe3QLCN`72GqZkH44K-*D^q4rjP#v JQ@9;z{|$n#Nyq>I literal 0 HcmV?d00001 diff --git a/controllers/__pycache__/localfile_handles.cpython-313.pyc b/controllers/__pycache__/localfile_handles.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81fa8cff70208dfd1a1648efbdd7f6b8aa37e8a8 GIT binary patch literal 1444 zcmah}&2Jk;6o0c{wwt7>oTO3%EtV4+)>Kw$Ymj0q$f8vdRia?W6v-CBu{WCy>s>Rm z#!U~E1BXW9LJ(CdF66+48z-cS1L8lRv}&qpI3P~BpnyTN5(nO_y$dN7j5KfGyzhPQ zH`5&&Is~|Wj%Tc|2*6L`5G<+Bbf=NI0Yxa1OF+d}x%M zD(X3@sE)&`LN$}<+MckO(+MABhSzE?+OBCDw1)Y@r6DKd?!JNKEzDL9wIw)5iUgxY z%Rxm@P(sg;Nx}kT`d%YpRe@v@bZPED$_RR%#ohfA$qbo*1g0&)2)z0(fJ4e*;6j)- z6hT4#n-94E@euhQTMJT&WctyALZ9o~)KNZr5uij0vB%u-7&N^w@NZo)Y{P+A4Zs1u z2RGCN%rbxh{9jXgNnR$ptV>sw^lH<*svRk ztG3%VD32OWowY4*MVGmhKFt;1WMJ8~>jqsEeoV|Xk?8PO&QDk7*Srk`J3rm(_iOyvh%mI^WVL`w3Dsr1{E{r5!+&3-J&|7!=ec+9x5^O-Q&-EcKOrG+vR)5 zU$`ATwxN7<;lb#!jq{?rQ=3y;r#4UB^zOt{cL!5A^|A3^WjJx>5flAv z(xHZ1H*A*fy;xMBnQOfRA2toIUq#JrIUXXwqkb)406mJ9!N@U2%Qj|c5@iAl>{%rH mG9lyv#D0L2KgPyBJkim9QRES+GrWIDCeLqA{0{i>!~6w~cpFmy literal 0 HcmV?d00001 diff --git a/controllers/compress_image.py b/controllers/compress_image.py new file mode 100644 index 0000000..644998c --- /dev/null +++ b/controllers/compress_image.py @@ -0,0 +1,52 @@ +import os +from PIL import Image +from models.logger import setup_logger + +logger = setup_logger() + +def compress_image(input_path, output_folder: str = 'compressed_images', target_kb=200, quality_step=5) -> str: + """ + 将图片压缩到指定大小(以KB为单位) + + Args: + input_path: 输入图片路径 + output_folder: 输出文件夹 + target_kb: 目标文件大小(默认200KB) + quality_step: 每次迭代中质量减少的步长(默认5) + + Returns: + 压缩后的图片路径 + """ + # 确保输出文件夹存在 + os.makedirs(output_folder, exist_ok=True) + + # 获取文件基本信息 + file_size_kb = os.path.getsize(input_path) / 1024 + base_name = os.path.basename(input_path) + output_path = os.path.join(output_folder, base_name.rsplit('.', 1)[0] + '.jpg') # 默认转为jpg + + if file_size_kb <= target_kb: + # 如果文件小于等于目标大小,直接复制 + img = Image.open(input_path) + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + img.save(output_path, "JPEG", optimize=True, quality=95) + return str(output_path) + + # 初始质量设置 + quality = 85 + + while quality > 10: # 设置最低质量限制避免过低质量的图片 + with Image.open(input_path) as img: + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + img.save(output_path, "JPEG", optimize=True, quality=quality) + + # 检查文件大小 + if os.path.getsize(output_path) / 1024 < target_kb: + return str(output_path) + + quality -= quality_step # 减少质量设置 + + logger.error(f"图片 {input_path} 压缩失败!") + return '' diff --git a/controllers/localfile_handles.py b/controllers/localfile_handles.py new file mode 100644 index 0000000..2c60c13 --- /dev/null +++ b/controllers/localfile_handles.py @@ -0,0 +1,14 @@ +import os +from models.logger import setup_logger + +logger = setup_logger() + +get_emoji_count = lambda folder_path: sum( + 1 for file in os.listdir(folder_path) + if os.path.isfile(os.path.join(folder_path, file)) and file.lower().endswith(('.jpg', '.jpeg')) +) + +def yield_emoji_path(folder_path: str): + for root, dirs, files in os.walk(folder_path): + for file in files: + yield os.path.join(root, file) diff --git a/controllers/logs/2025-12-07.log b/controllers/logs/2025-12-07.log new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py new file mode 100644 index 0000000..cb0f617 --- /dev/null +++ b/main.py @@ -0,0 +1,17 @@ +import os +from dashscope import MultiModalConversation +import dashscope + +# 本地图像的绝对路径 +local_path = r"D:\Python\mcunc\EmojiTextGenerator\emojis\00e4f193-74af-40f7-8722-59d5a5931f92.jpg" +image_path = f"file://{local_path}" +messages = [ + {'role':'user', + 'content': [{'image': image_path}, + {'text': '使用简洁语言描述该表情包 ,例如 在吗 ,生气,?'}]}] +response = MultiModalConversation.call( + api_key="sk-213f83213fce4e2ba41b8e67721f19cb", + model='qwen3-vl-plus', + messages=messages) + +print(response.output.choices[0].message.content[0]["text"]) diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/__pycache__/__init__.cpython-313.pyc b/models/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1108e1090e4e6b0ff12686247e7a4a3ca113268 GIT binary patch literal 150 zcmey&%ge<81m8SNGC}lX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~iUi&acOWl2VU zUQBLsXsbi~s-t literal 0 HcmV?d00001 diff --git a/models/__pycache__/connect_db.cpython-313.pyc b/models/__pycache__/connect_db.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..396feba2057c323fd5c8d40fe5eb01d83139f2dd GIT binary patch literal 3706 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 Connection | None: + """连接数据库,如果没有则初始化数据库和表""" + try: + config = toml.load("../config.toml") + db_host = config["db_host"] + db_port = config["db_port"] + db_user = config["db_user"] + db_password = config["db_password"] + db_database = config["db_database"] + except Exception as e: + logger.error(f"读取数据库配置错误{e}") + return None + + connection = pymysql.connect( + host=db_host, + port=int(db_port), + user=db_user, + password=db_password, + database=db_database, + charset='utf8mb4', + cursorclass=DictCursor + ) + + try: + with connection.cursor() as cursor: + # 创建 emoji 表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS emoji ( + id INT AUTO_INCREMENT PRIMARY KEY, + uuid VARCHAR(255) NOT NULL, + description VARCHAR(255), + url VARCHAR(255) NOT NULL, + hash VARCHAR(255) NOT NULL + ) + ''') + + # 创建 approved 表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS approved + ( + id INT AUTO_INCREMENT PRIMARY KEY, + uuid VARCHAR(255) NOT NULL, + approved BOOL, + approver VARCHAR(255) + ) + ''') + + # 创建 token 表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS token + ( + id INT AUTO_INCREMENT PRIMARY KEY, + token VARCHAR(255) NOT NULL , + userid INT NOT NULL , + expires TIMESTAMP NOT NULL + ) + ''') + + # 创建 user 表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS user + ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(255) NOT NULL, + passwd VARCHAR(255) NOT NULL, + email VARCHAR(255), + lastlogin TIMESTAMP, + submission_count INT DEFAULT 0 + ) + ''') + + return connection + except Exception as e: + logger.error(f"数据库连接或表创建失败: {e}") + return None + + +if __name__ == "__main__": + conn = connect_db() + conn.cursor() \ No newline at end of file diff --git a/models/emoji_db.py b/models/emoji_db.py new file mode 100644 index 0000000..853321c --- /dev/null +++ b/models/emoji_db.py @@ -0,0 +1,73 @@ +from models.connect_db import connect_db +from models.logger import setup_logger + +logger = setup_logger() +connection = connect_db() + +def update_description(emoji_uuid: str, description: str) -> bool: + """ + 更新表情包描述词 + + Args: + emoji_uuid: 表情包UUID + description: 新的描述词 + + Returns: + 成功返回True,失败返回False + """ + try: + sql = """ + UPDATE emoji + SET description = %s + WHERE uuid = %s + """ + + params = (description, emoji_uuid) + + with connection.cursor() as cursor: + affected_rows = cursor.execute(sql, params) + + if affected_rows > 0: + logger.info(f"成功更新表情包描述,UUID: {emoji_uuid}") + return True + else: + logger.warning(f"未找到要更新的表情包,UUID: {emoji_uuid}") + return False + + except Exception as e: + logger.error(f"更新表情包描述失败: {e}") + return False + + +def check_emoji(uuid: str) -> bool: + """ + 检查UUID是否存在于emoji表中 + + Args: + uuid: 要检查的UUID字符串 + + Returns: + uuid 在数据库中存在则为 True,否则 False + """ + # 参数验证 + if not uuid or not isinstance(uuid, str): + logger.warning(f"无效的UUID参数: {uuid}") + return False + + try: + with connection.cursor() as cursor: + # 执行查询 + sql = "SELECT 1 FROM emoji WHERE uuid = %s LIMIT 1" + cursor.execute(sql, (uuid,)) + + # 如果查询到结果则返回True + result = cursor.fetchone() + return result is not None + + except Exception as e: + logger.error(f"检查UUID失败: {uuid}, 错误: {e}") + return False + +if __name__ == "__main__": + record = check_emoji("ffe1663c-44e1-4719-a5ba-01485f70a87e") + print(record) \ No newline at end of file diff --git a/models/generator.py b/models/generator.py new file mode 100644 index 0000000..c6c7f2d --- /dev/null +++ b/models/generator.py @@ -0,0 +1,44 @@ +import os +from typing import Optional +from dashscope import MultiModalConversation +from models.logger import setup_logger + +logger = setup_logger() + +class Generator: + def __init__(self, api_key: str, model: str = 'qwen3-vl-plus'): + self.api_key = api_key + self.model = model + + def process_single_image(self, image_path: str) -> Optional[str]: + """处理单张图片,生成描述词""" + try: + image_url = f"file://{image_path}" + messages = [ + { + 'role': 'user', + 'content': [ + {'image': image_url}, + {'text': '使用简洁语言描述该表情包 ,例如 在吗 ,生气,?'} + ] + } + ] + + response = MultiModalConversation.call( + model=self.model, + messages=messages + ) + + if response and hasattr(response, 'output'): + if hasattr(response.output.choices[0].message.content[0], 'text'): + return response.output.choices[0].message.content[0]["text"] + elif isinstance(response.output.choices[0].message.content[0], dict): + return response.output.choices[0].message.content[0].get("text", "") + + return None + + except Exception as e: + logger.error(f"API调用失败: {e}") + return None + + diff --git a/models/logger.py b/models/logger.py new file mode 100644 index 0000000..832c393 --- /dev/null +++ b/models/logger.py @@ -0,0 +1,61 @@ +import logging +from logging.handlers import RotatingFileHandler +from datetime import datetime +from pathlib import Path + +def setup_logger(log_file=None, log_level=logging.INFO, max_bytes=10485760, backup_count=5): + """ + 初始化日志记录器,将日志按指定格式输出并记录到文件 + + Args: + log_file (str): 日志文件路径,默认为None,会自动生成以当天日期命名的日志文件 + log_level: 日志级别 + max_bytes (int): 单个日志文件最大字节数 + backup_count (int): 保留的备份日志文件数量 + + Returns: + logging.Logger: 配置好的日志记录器 + """ + # 创建logger + logger = logging.getLogger('emoji-text-generator') + logger.setLevel(log_level) + logger.propagate = False + + # 避免重复添加handler + if logger.handlers: + return logger + + # 创建logs目录(如果不存在) + log_dir = Path('logs') + log_dir.mkdir(exist_ok=True) + + # 如果未指定日志文件名,则使用当天日期命名 + if log_file is None: + today = datetime.now().strftime('%Y-%m-%d') + log_file = log_dir / f'{today}.log' + + # 创建格式化器 + formatter = logging.Formatter( + '[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] - %(message)s' + ) + + # 创建文件处理器(带轮转) + file_handler = RotatingFileHandler( + log_file, + maxBytes=max_bytes, + backupCount=backup_count, + encoding='utf-8' + ) + file_handler.setLevel(log_level) + file_handler.setFormatter(formatter) + + # 创建控制台处理器 + console_handler = logging.StreamHandler() + console_handler.setLevel(log_level) + console_handler.setFormatter(formatter) + + # 添加处理器到logger + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + return logger \ No newline at end of file diff --git a/models/logs/2025-12-07.log b/models/logs/2025-12-07.log new file mode 100644 index 0000000..c681502 --- /dev/null +++ b/models/logs/2025-12-07.log @@ -0,0 +1,2 @@ +[2025-12-07 13:44:14,574] [ERROR] [connect_db.py:19] - 读取数据库配置错误[Errno 2] No such file or directory: 'config.toml' +[2025-12-07 13:44:14,574] [ERROR] [emoji_db.py:68] - 检查表情包是否存在失败: 'NoneType' object has no attribute 'cursor' diff --git a/test.py b/test.py new file mode 100644 index 0000000..4a5ab9e --- /dev/null +++ b/test.py @@ -0,0 +1,36 @@ +import os +from pathlib import Path +from models.generator import Generator +from models.emoji_db import check_emoji, update_description +from controllers.localfile_handles import get_emoji_count, yield_emoji_path +from controllers.compress_image import compress_image +from models.logger import setup_logger + +logger = setup_logger() + +emoji_folders = "D:\\Python\\mcunc\\EmojiTextGenerator\\emojis\\" +emoji = yield_emoji_path(emoji_folders) + +api_key = os.getenv('DASHSCOPE_API_KEY') + +def main(): + gen = Generator(api_key) + for f in range(get_emoji_count(emoji_folders)): + emoji_file = next(emoji) + emoji_uuid = '' + p = Path(emoji_file) + if p.suffix == ".jpg" or p.suffix == ".jpeg": + emoji_uuid = p.stem + # print(emoji_uuid) + image = compress_image(emoji_file) + + # if not check_emoji(emoji_uuid): + # logger.error(f"图片 {emoji_uuid} 不在数据库中!") + # else: + description = gen.process_single_image(image) + if update_description(emoji_uuid, description) + logger.info(f"图片 {emoji_file} 的描述词生成完毕, 其 description 为: {description}") + + +if __name__ == "__main__": + main()