├── README.md ├── Trickle-On-WeChat ├── AIGCaaS │ ├── PaddleOCR.py │ ├── Tragger.py │ └── resnest101.py ├── ApS │ └── Img2Text.py ├── CONFIG.py ├── FetchAPI │ └── ChatGPT.py ├── PICS │ └── 230915-111455.png └── Robot.py └── requirements /README.md: -------------------------------------------------------------------------------- 1 | # Trickle-On-WeChat 2 | 在微信端使用类似Trickle的图片信息识别和提炼,并进行图片信息管理的功能。 3 | > 思路介绍:https://mp.weixin.qq.com/s/Q9ubSQHhEgpn2Yf6ndoi5w 4 | 5 | ## 功能演示: 6 | 7 | 8 | 9 | https://github.com/PromptExpert/Trickle-On-WeChat/assets/46588426/40c83e2e-66ab-474b-a464-878b3e63a4df 10 | 11 | 12 | 13 | 14 | 图片识别自动提取关键信息 15 | ![image](https://github.com/PromptExpert/Trickle-On-WeChat/assets/46588426/d6b01120-0921-4dad-a8d9-245e2c55e7ed) 16 | 17 | 利用微信聊天记录关键词搜索定位关键信息: 18 | ![image](https://github.com/PromptExpert/Trickle-On-WeChat/assets/46588426/b5a7c8a9-d89d-4a7a-9506-14b2e454b071) 19 | 20 | ## 语言支持 21 | Python 3.6.x ~ 3.7.x 22 | 23 | ## 依赖包 24 | ``` 25 | certifi==2023.5.7 26 | charset-normalizer==3.1.0 27 | future==0.18.3 28 | idna==3.4 29 | itchat==1.2.32 30 | itchat-uos==1.5.0.dev0 31 | pypng==0.20220715.0 32 | PyQRCode==1.2.1 33 | requests==2.30.0 34 | urllib3==2.0.2 35 | wxpy==0.3.9.8 36 | ``` 37 | 38 | ## 环境支持 39 | MacOs、Windows、Linux 40 | 41 | ## 使用说明 42 | ⚠️ Python环境请务必保持在 3.6.x-3.7.x 版本,我使用的是3.7.0(惨痛教训:wxpy这个库对Python的版本有要求) 43 | 44 | - Step1:解压下载当前项目,并安装相关Python依赖 45 | - Step2:根据Config中的信息,配置语言模型的Key、配置图像识别及OCR的Key 46 | - Step3:运行Robot.py主程序 47 | - Step4:程序启动后,通过手机扫描二维码的方式进行登录(若失败请反复扫描) 48 | 49 | ## 主要是用的wxpy库,中文文档(已停更) 50 | 该库的核心使用的是itchat,是通过网页扫码的方式登陆微信。 51 | ``` 52 | https://wxpy.readthedocs.io/zh/latest/ 53 | ``` 54 | 55 | ## API供应商 56 | Paddle OCR + 图像识别:AIGCaaS主要为本项目提供了OCR的接口能力以及图像识别的能力,费用也相对来说较低,注册地址:https://www.aigcaas.cn/home_v3/login?share=AEjMzBfmyA 57 | -------------------------------------------------------------------------------- /Trickle-On-WeChat/AIGCaaS/PaddleOCR.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import hashlib 4 | import random 5 | import requests 6 | import CONFIG 7 | 8 | secret_id = CONFIG.SECRET_ID # 密钥信息 9 | secret_key = CONFIG.SECRET_KEY # 密钥信息 10 | 11 | def Img_To_Text(image_url = None,image_base64 = None): 12 | # 签名对象 13 | getSha256 = lambda content: hashlib.sha256(content.encode("utf-8")).hexdigest() 14 | 15 | # 请求地址 16 | url = "https://api.aigcaas.cn/v3/application/image_recognition/action/paddleocr" 17 | # 构建请求头 18 | nonce = str(random.randint(1, 10000)) 19 | timestamp = str(int(time.time())) 20 | token = getSha256(("%s%s%s" % (timestamp, secret_key, nonce))) 21 | headers = { 22 | 'SecretID': secret_id, 23 | 'Nonce': nonce, 24 | 'Token': token, 25 | 'Timestamp': timestamp, 26 | 'Content-Type': 'application/json' 27 | } 28 | 29 | # 构建请求 body,可以自行根据上面的内容,添加更多参数 30 | data = { 31 | "image_base64": image_base64, 32 | "image_url": image_url, 33 | "ocr_type": "ocr" 34 | } 35 | 36 | # 获取响应 37 | response = requests.request("POST", url, headers=headers, data=json.dumps(data)) 38 | response_dict = json.loads(response.text) 39 | if response_dict['status'] == 'Success': 40 | res_msg = response_dict["data"] 41 | return res_msg 42 | else: 43 | return -1 44 | 45 | if __name__ == '__main__': 46 | Img_To_Text(image_url="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.alicdn.com%2Fi4%2F1620781558%2FO1CN01n5ye621NNbcxW0FZB_%21%211620781558.jpg&refer=http%3A%2F%2Fimg.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1697287866&t=821b97b3cdaef29c00872a10e1f0e050") -------------------------------------------------------------------------------- /Trickle-On-WeChat/AIGCaaS/Tragger.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import hashlib 4 | import random 5 | import requests 6 | import CONFIG 7 | import base64 8 | 9 | 10 | secret_id = CONFIG.SECRET_ID # 密钥信息 11 | secret_key = CONFIG.SECRET_KEY # 密钥信息 12 | 13 | 14 | def img2text(img_path): 15 | # 将图片转换为Base64字符串 16 | with open(img_path, "rb") as f: 17 | base64_image = base64.b64encode(f.read()).decode("utf-8") 18 | # 签名对象 19 | getSha256 = lambda content: hashlib.sha256(content.encode("utf-8")).hexdigest() 20 | application_name = 'sdtagger' # 应用名称 21 | api_name = 'tagger' # 接口名称 22 | 23 | # 请求地址 24 | url = "https://api.aigcaas.cn/v2/application/%s/api/%s" % (application_name, api_name) 25 | # 构建请求头 26 | nonce = str(random.randint(1, 10000)) 27 | timestamp = str(int(time.time())) 28 | token = getSha256(("%s%s%s" % (timestamp, secret_key, nonce))) 29 | headers = { 30 | 'SecretID': secret_id, 31 | 'Nonce': nonce, 32 | 'Token': token, 33 | 'Timestamp': timestamp, 34 | 'Content-Type': 'application/json' 35 | } 36 | # 构建请求 body 37 | data = { 38 | "model": "wd14-vit-v2-git", 39 | "image": "data:image/png;base64," + str(base64_image) 40 | } 41 | 42 | # 获取响应 43 | response = requests.request("POST", url, headers=headers, data=json.dumps(data)) 44 | request_id = response.headers["Aigcaas-Request-Id"] 45 | # 任务开始时间 46 | start_time = time.time() 47 | while True: 48 | time.sleep(3) 49 | if time.time() - start_time > 300: # 如果时间超过5分钟 50 | print("Failed to Image2Text within 5 minutes.") 51 | break 52 | url = "https://api.aigcaas.cn/v2/async" 53 | # 构建请求头 54 | nonce = str(random.randint(1, 10000)) 55 | timestamp = str(int(time.time())) 56 | token = getSha256(("%s%s%s" % (timestamp, secret_key, nonce))) 57 | headers = { 58 | 'SecretID': secret_id, 59 | 'RequestID': request_id, 60 | 'Nonce': nonce, 61 | 'Token': token, 62 | 'Timestamp': timestamp, 63 | 'Content-Type': 'application/json' 64 | } 65 | async_response = requests.request("GET", url, headers=headers, data=json.dumps(data)) 66 | print(async_response.status_code, async_response.content) 67 | if async_response.status_code != 202: 68 | # 如果是413则直接失败 69 | if async_response.status_code == 413: 70 | print("程序出现异常:{}".format(async_response.content)) 71 | response_content = json.loads(async_response.content) 72 | # print(response_content) 73 | tags = response_content["tags"] 74 | sorted_tags = sorted(tags.items(), key=lambda x: x[1], reverse=True) 75 | top_25_keys = [item[0] for item in sorted_tags[:25]] 76 | prompts = ', '.join(str(x) for x in top_25_keys) 77 | # print(prompts) 78 | return prompts 79 | break 80 | 81 | if __name__ == '__main__': 82 | prompts = img2text("/Users/joseph/Desktop/TuTu/PICS/1.png") 83 | print(prompts) -------------------------------------------------------------------------------- /Trickle-On-WeChat/AIGCaaS/resnest101.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import hashlib 4 | import random 5 | import requests 6 | import CONFIG 7 | 8 | secret_id = CONFIG.SECRET_ID # 密钥信息 9 | secret_key = CONFIG.SECRET_KEY # 密钥信息 10 | 11 | def describe(image_url = None,image_base64 = None): 12 | # 签名对象 13 | getSha256 = lambda content: hashlib.sha256(content.encode("utf-8")).hexdigest() 14 | 15 | # 请求地址 16 | url = "https://api.aigcaas.cn/v3/application/image_recognition/action/resnest101" 17 | # 构建请求头 18 | nonce = str(random.randint(1, 10000)) 19 | timestamp = str(int(time.time())) 20 | token = getSha256(("%s%s%s" % (timestamp, secret_key, nonce))) 21 | headers = { 22 | 'SecretID': secret_id, 23 | 'Nonce': nonce, 24 | 'Token': token, 25 | 'Timestamp': timestamp, 26 | 'Content-Type': 'application/json' 27 | } 28 | 29 | # 构建请求 body,可以自行根据上面的内容,添加更多参数 30 | data = { 31 | "image_url":image_url, 32 | "image_base64":image_base64, 33 | } 34 | 35 | # 获取响应 36 | response = requests.request("POST", url, headers=headers, data=json.dumps(data)) 37 | response_dict = json.loads(response.text) 38 | # print(response_dict) 39 | if "error" in response_dict: 40 | return -1 41 | elif response_dict['status'] == 'Success': 42 | res_msg = response_dict["data"]["labels"] 43 | return res_msg 44 | else: 45 | return -1 46 | 47 | if __name__ == '__main__': 48 | res = describe(image_url = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.alicdn.com%2Fi4%2F1620781558%2FO1CN01n5ye621NNbcxW0FZB_%21%211620781558.jpg&refer=http%3A%2F%2Fimg.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1697287866&t=821b97b3cdaef29c00872a10e1f0e050") 49 | print(res) -------------------------------------------------------------------------------- /Trickle-On-WeChat/ApS/Img2Text.py: -------------------------------------------------------------------------------- 1 | from AIGCaaS import PaddleOCR,resnest101 2 | from FetchAPI import ChatGPT 3 | import base64 4 | 5 | # 图片信息提炼并总结函数(核心服务) 6 | def Img_Summary(img_path): 7 | try: 8 | print("正在执行图片解析任务...") 9 | # 将图片转换为Base64字符串 10 | with open(img_path, "rb") as f: 11 | base64_image = base64.b64encode(f.read()).decode("utf-8") 12 | text = PaddleOCR.Img_To_Text(image_base64 = base64_image) 13 | # print(text) 14 | desc = resnest101.describe(image_base64 = base64_image) 15 | # print(desc) 16 | 17 | sys_prompt = """ 18 | - 你会将图片通过OCR后的文本信息整合总结,请一步一步思考,你会挖掘不同单词和信息之间的联系, 19 | 你会用各种信息分析方法(如:统计、聚类...等)完成信息整理任务,翻译成中文回复。 20 | - 输出格式: 21 | " 22 | # 标题 23 | {填充信息:通过一句话概括成标题,不超过15字} 24 | 25 | # 概要 26 | {填充信息:通过一句话描述整体内容,不超过30字} 27 | 28 | {填充信息:分点显示,整合信息后总结,最多不超过8点,每条信息不超过20字,保留关键值,如人名、地名...} 29 | 30 | # 标签 31 | {填充信息:为该信息3-5个分类标签,例如:#科学、#艺术、#文学、#科技} 32 | " 33 | """ 34 | try: 35 | print("正在执行图片总结任务...") 36 | user_msg = "这张图是{},图中文字信息:{}".format(desc,text) 37 | summary = ChatGPT.GPT3_5(sys_prompt = sys_prompt,user_msg = user_msg) 38 | if summary == -1: 39 | return "我已经睡了,别喊我起来!" 40 | else: 41 | return summary 42 | except Exception as e: 43 | print("ChatGPT总结任务失败:{}".format(e)) 44 | return -1 45 | except: 46 | return -1 47 | 48 | if __name__ == '__main__': 49 | res = Img_Summary("/Users/joseph/Desktop/TuTu/PICS/230915-111455.png") 50 | print(res) -------------------------------------------------------------------------------- /Trickle-On-WeChat/CONFIG.py: -------------------------------------------------------------------------------- 1 | # 群聊名称 2 | GROUPS = ['AGI LAB'] 3 | 4 | # FetchAPI key 5 | # 在本项目中,我是用的是FetchAPI,使用的是GTP3.5模型,在下面可以填入你的FetchAPI的Key信息,或者您可以接入自己的ChatGPT服务或其他大模型API。 6 | # FetchAPI注册地址https://frostsnowjh.com/#/?share=10000817 7 | 8 | API_KEY = ‘您的FetchAPI Key’ 9 | 10 | 11 | # AIGCaaS openApi key 12 | # AIGCaaS主要为本项目提供了OCR的接口能力以及图像识别的能力,费用也相对来说较低,注册地址:https://www.aigcaas.cn/home_v3/login?share=AEjMzBfmyA 13 | 14 | SECRET_ID = '您的AIGCaaS SECRET_ID' 15 | SECRET_KEY= '您的AIGCaaS SECRET_ID' 16 | 17 | 18 | # 图片存放的地址,自定义您的图片存放地址 19 | 20 | PICS_DIC = '/Users/joseph/Desktop/TuTu/PICS/' 21 | 22 | MAX_LINE = 10 -------------------------------------------------------------------------------- /Trickle-On-WeChat/FetchAPI/ChatGPT.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import datetime 3 | import CONFIG 4 | 5 | 6 | def GPT3_5(sys_prompt=None, user_msg=None, user_name=None, user_puid=None): 7 | current_contents = [{"role": "system", "content": sys_prompt}, 8 | {"role": "user", "content": user_msg}] 9 | # 当前时间 10 | now_time = datetime.datetime.now() 11 | # 格式化输出时间 12 | format_time = now_time.strftime('%Y-%m-%d %H:%M:%S') 13 | header = { 14 | "Content-Type": "application/json", 15 | "Authorization": "Bearer " + CONFIG.API_KEY 16 | } 17 | post_dict = { 18 | "model": "gpt-3.5-turbo-16k", 19 | "temperature": 0.8, 20 | "max_tokens": 600, 21 | "stream": False, 22 | "messages": current_contents 23 | } 24 | try: 25 | response = requests.post("https://frostsnowjh.com/v1/chat/completions", json=post_dict, headers=header) 26 | if 'error' in response.json() or '504' in response: 27 | print(response.content) 28 | return "error" 29 | message = response.json()["choices"][0]["message"] 30 | if 'content' in message: 31 | content = message["content"] 32 | return content 33 | else: 34 | return -1 35 | except Exception as e: 36 | print(e) 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | sys_prompt = "" 42 | user_msg = "一条蜿蜒的小溪" 43 | result = GPT3_5(sys_prompt,user_msg) 44 | print(result) -------------------------------------------------------------------------------- /Trickle-On-WeChat/PICS/230915-111455.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhai-wiki/Trickle-On-WeChat/1e3bca4be81428f59a6de4cc3a11b763cede0bc1/Trickle-On-WeChat/PICS/230915-111455.png -------------------------------------------------------------------------------- /Trickle-On-WeChat/Robot.py: -------------------------------------------------------------------------------- 1 | import os 2 | from PIL import Image 3 | from wxpy import * 4 | import logging 5 | import CONFIG 6 | from concurrent.futures import ThreadPoolExecutor 7 | from FetchAPI import ChatGPT 8 | from ApS import Img2Text 9 | import time 10 | 11 | bot = Bot(cache_path=True) 12 | bot.enable_puid('bot.pkl') 13 | 14 | print("TuTu is running...") 15 | 16 | # 收到前一条信息的时间 17 | prev_msg_time = None 18 | # 已经处理的任务集合 19 | task_map = [] 20 | 21 | """ 22 | 日志功能 23 | """ 24 | fh = logging.FileHandler('wxpy.log', encoding='utf-8') 25 | logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s:%(message)s', handlers=[fh]) 26 | 27 | 28 | # 监听并接收好友消息 29 | @bot.register(Friend) 30 | def auto_reply(msg): 31 | global prev_msg_time 32 | # 当前消息的时间 33 | msg_time = int(msg.create_time.timestamp()) 34 | # 当前时间 35 | current_time = int(time.time()) 36 | # 只处理60秒内的信息 37 | if current_time - msg_time < 60: 38 | # 图片消息 39 | if msg.type == 'Picture': 40 | user_name = msg.chat.nick_name 41 | user_puid = msg.sender.puid 42 | file_name = msg.file_name 43 | try: 44 | if file_name not in task_map: 45 | task_map.append(file_name) 46 | file = msg.get_file() 47 | file_path = CONFIG.PICS_DIC + file_name 48 | msg.reply("🔍 Observing...") 49 | if '.gif' not in file_name: 50 | with open(file_path, 'wb', buffering=4096000) as f: 51 | f.write(file) 52 | print('{}:{} 的图片已保存:{}'.format(user_name, user_puid, file_path)) 53 | # 验证图片尺寸 54 | image = Image.open(file_path) 55 | res = Img2Text.Img_Summary(file_path) 56 | msg.reply(res) 57 | except Exception as e: 58 | print("{}的图片存储过程中发生错误:{}".format(user_name, e)) 59 | 60 | 61 | 62 | # 最大线程池数目 解决并发问题 63 | # thread_pool = ThreadPoolExecutor(max_workers=CONFIG.MAX_LINE) 64 | 65 | bot.join() -------------------------------------------------------------------------------- /requirements: -------------------------------------------------------------------------------- 1 | certifi==2023.5.7 2 | charset-normalizer==3.1.0 3 | future==0.18.3 4 | idna==3.4 5 | itchat==1.2.32 6 | itchat-uos==1.5.0.dev0 7 | pypng==0.20220715.0 8 | PyQRCode==1.2.1 9 | requests==2.30.0 10 | urllib3==2.0.2 11 | wxpy==0.3.9.8 12 | --------------------------------------------------------------------------------