终极需求: 做一个专属于我的知识库。这个嘛,只是这个终极需求的第一步。这个仅仅是作为 demo,后面还有如山一样多的事情要做。
(先来一个最终的效果图看看)
在开始之前,你需要确保已经安装 Python 3。你还需要以下内容:
pip install telethon PySocks
安装。import csv
import socks
from telethon import TelegramClient
from telethon.tl.functions.messages import GetHistoryRequest
# 设置 TelegramClient,连接到 Telegram API
client = TelegramClient(
'demo',
'api_id',
'api_hash',
proxy=(socks.SOCKS5, '127.0.0.1', 1080)
)
async def export_to_csv(filename, fieldnames, data):
"""
将数据导出到 CSV 文件中。
参数:
filename -- 导出文件的名称
fieldnames -- CSV 头部字段名称列表
data -- 要导出的字典列表
"""
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
async def fetch_messages(channel_username):
"""
获取指定频道的所有消息。
参数:
channel_username -- 目标频道的用户名
"""
channel_entity = await client.get_input_entity(channel_username)
offset_id = 0 # 初始消息 ID 偏移量
all_messages = [] # 存储所有消息的列表
while True:
# 请求消息记录
history = await client(GetHistoryRequest(
peer=channel_entity,
offset_id=offset_id,
offset_date=None,
add_offset=0,
limit=100, # 每次请求的消息数量
max_id=0,
min_id=0,
hash=0
))
if not history.messages: # 当没有更多消息时结束循环
break
for message in history.messages:
if message.message: # 仅处理有文本内容的消息
# 将消息序列化为字典形式
message_dict = {
'id': message.id,
'date': message.date.strftime('%Y-%m-%d %H:%M:%S'),
'text': message.message
}
all_messages.append(message_dict)
offset_id = history.messages[-1].id
print(f"Fetched messages: {len(all_messages)}")
return all_messages
async def main():
"""
主程序:从指定频道获取消息并保存到 CSV 文件中。
"""
await client.start() # 启动 Telegram 客户端
print("Client Created")
channel_username = 'niracler_channel' # 你要抓取的 Telegram 频道用户名
all_messages = await fetch_messages(channel_username) # 获取消息
# 定义 CSV 文件的头部,并导出
headers = ['id', 'date', 'text']
await export_to_csv('channel_messages.csv', headers, all_messages)
# 当该脚本作为主程序运行时
if __name__ == '__main__':
client.loop.run_until_complete(main())
在终端运行脚本:
python telegram_to_csv.py
脚本会开始运行,并将来自指定 Telegram 频道的所有消息保存到当前目录下名为 channel_messages.csv 的文件中。
完成以上步骤后,你将在 channel_messages.csv 文件中找到频道内的文本消息,包括消息的 ID、日期及其内容。
(结果就不贴出来了~~)
pip install openai pandas
安装。将下面的 Python 脚本保存为 embedding_generator.py:
import pandas as pd
from openai import OpenAI
# 配置 OpenAI 客户端
client = OpenAI(api_key='YOUR_API_KEY')
def get_embedding(text, model="text-embedding-ada-002"):
"""
获取文本的嵌入向量。
"""
text = text.replace("\n", " ") # 清理文本中的换行符
response = client.embeddings.create(input=[text], model=model) # 请求嵌入向量
return response.data[0].embedding # 提取和返回嵌入向量
def embedding_gen():
"""
生成教程文本嵌入向量数据。
"""
df = pd.read_csv('channel_messages.csv') # 读取 CSV 文件到 DataFrame
df['text_with_date'] = df['date'] + " " + df['text'] # 拼接日期和文本
df['ada_embedding'] = df[:100].text_with_date.apply(get_embedding) # 批量应用文本嵌入函数
del df['text_with_date'] # 删除 'text_with_date' 列
df.to_csv('embedded_1k_reviews.csv', index=False) # 保存结果到新的 CSV 文件
# 打印 DataFrame 的前几行进行确认
print(df.head())
# 当脚本被直接运行时
if __name__ == "__main__":
embedding_gen()
python embedding_generator.py
pip install pandas numpy tabulate
安装。将下面的 Python 脚本保存为 embedding_search.py:
import ast
import sys
import pandas as pd
import numpy as np
from tabulate import tabulate
from openai import OpenAI
# 配置 OpenAI 客户端
client = OpenAI(api_key='YOUR_API_KEY')
def get_embedding(text, model="text-embedding-ada-002"):
"""
获取文本的嵌入向量。
"""
text = text.replace("\n", " ") # 清理文本中的换行符
response = client.embeddings.create(input=[text], model=model) # 请求嵌入向量
return response.data[0].embedding # 提取和返回嵌入向量
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
def embedding_search(query, df, model="text-embedding-ada-002"):
"""
使用 OpenAI API 搜索嵌入向量。
"""
query_embedding = get_embedding(query, model=model) # 获取查询文本的嵌入向量
df['similarity'] = df.ada_embedding.apply(lambda x: cosine_similarity(ast.literal_eval(x), query_embedding)) # 计算相似度
df = df.sort_values(by='similarity', ascending=False) # 按相似度降序排列
df = df.drop(columns=['ada_embedding']) # 删除嵌入向量列
return df
if __name__ == "__main__":
df = pd.read_csv('embedded_1k_reviews.csv') # 读取 CSV 文件到 DataFrame
query = sys.argv[1]
df = embedding_search(query, df) # 搜索嵌入向量
print(tabulate(df.head(10), headers='keys', tablefmt='psql')) # 打印前 10 条结果
$ python embedding_search.py 动物森友会
+------+---------------------+--------------------------------------------------------------+----------------+
| | date | text | similarities |
|------+---------------------+--------------------------------------------------------------+----------------|
| 1041 | 2021-04-03 06:18:40 | 尼尔 森友会 | 0.843896 |
| 836 | 2021-10-16 02:37:16 | 动森直面会中文视频 | 0.826405 |
| | | https://www.youtube.com/watch?v=rI_jWfNd2dc | |
| 1208 | 2019-11-10 00:05:56 | 云养动物好像很有趣啊 | 0.822377 |
| 489 | 2023-06-16 09:33:15 | 看着小猫的生活就想起西西佛神话里面的西西佛 | 0.802677 |
| 369 | 2023-08-16 02:15:54 | 家猫会不会无聊寂寞 | 0.797062 |
| 13 | 2023-12-14 13:17:59 | 参加了🤗 | 0.796492 |
| 1177 | 2020-02-12 10:27:45 | 国人吃野生动物这种事情之所以屡屡不绝,和头脑中根深蒂固的中医 | 0.796363 |
| | | 观念亦有直接关系。养生、食疗、进补、药膳、以形补形、补气血…… | |
| | | 伪科学死灰复燃,现在不加以遏制,以后也还会发生类似的事情。 | |
| | | 科学才是唯一的道路。 | |
| 801 | 2021-11-07 13:46:21 | 想不到,今年的年度游戏竟然还是动森跟火纹。 | 0.796246 |
| | | 动森是之前没玩够,火纹是因为某个最大最恶事件导致我要重玩的。 | |
| 837 | 2021-10-16 02:37:16 | 不会吧,难道我的年度游戏又要变成动森了吗? | 0.795871 |
| 423 | 2023-07-29 14:11:22 | 鬼畜到能称之为精神污染的头像了~~ | 0.794144 |
+------+---------------------+--------------------------------------------------------------+----------------+
也是一个没有什么技术含量的文章,算是记录了我又学到了一些东西吧。