起因
我应该是有点收集癖的,github上面已经点了 1.4k 的star了,自己分类一千四百个东西着实头大,想到可以交给ai,所以就做了这么个玩意
效果

分类效果如上图
具体的分类内容已经在 awesome-stars-LIPiston 展示出来,欢迎大家来看
代码主体长这样,用了gemini-cli来进行分类,写代码的过程中我也吃了点ai饭XD
import json
import subprocess
import os
# 您的分类指南,作为提示词的一部分
PROMPT_GUIDE = """
GitHub仓库分类指南
作为AI,当你收到一个GitHub仓库列表时,请根据以下指南对仓库进行分类。如果仓库不符合任何现有类别,请基于仓库内容创建新类别。输出应为完整的Markdown文档,包括所有类别和仓库信息。
现有类别及关键词
以下是预定义类别及其常见关键词,用于匹配仓库:
• 网页工具: 与Web开发、在线服务、浏览器扩展、前端/后端工具相关。关键词:web、前端、后端、浏览器、扩展、工具、在线、代理、监控、API、云服务、部署。
• 安卓app: 针对Android平台的应用程序。关键词:android、app、应用、移动、手机、播放器、下载器、工具、ROM、模块。
• fonts: 字体设计、字体库或字体相关工具。关键词:font、字体、typography、bitmap、像素字体。
• libs: 库、框架或开发工具。关键词:library、framework、库、框架、开发工具、SDK、API、组件。
• Minecraft: 与Minecraft游戏相关的项目。关键词:minecraft、游戏、服务器、插件、模组、启动器、联机。
• tg: 与Telegram相关的项目。关键词:telegram、tg、机器人、客户端、消息、聊天。
• qq: 与QQ或腾讯相关的项目。关键词:qq、腾讯、机器人、客户端、插件、QQ频道。
• magisk: 与Magisk相关的项目。关键词:magisk、root、模块、系统、优化、安全、刷机。
• lsposed: 与LSPosed或Xposed相关的项目。关键词:lsposed、xposed、模块、hook、注入、修改。
• themes: 主题、皮肤或UI定制相关。关键词:theme、主题、皮肤、UI、美化、定制。
分类规则
1. 读取仓库信息: 获取每个仓库的名称、描述、主要语言、星标数、作者和链接。
2. 关键词匹配: 根据描述中的关键词和仓库用途,匹配到最合适的现有类别。优先使用描述中的关键词,其次考虑语言和项目类型。
3. 创建新类别: 如果仓库不匹配任何现有类别,基于仓库内容创建新类别。新类别名称应简洁明了,反映仓库的主要用途(如“硬件”、“AI”、“游戏”等)。
4. 输出格式: 使用Markdown格式输出,每个类别以##开头,仓库列表使用无序列表(•),每个仓库包括名称(链接)、星标数、语言、作者和描述。
输出格式要求
对于每个类别,输出如下:
## 📂 类别名称 (数量 Repos)
• [`仓库名称`](仓库链接) ★星标数 — *主要语言* — _作者_
> 描述
"""
def call_gemini_cli(prompt_text):
"""
通过 os.system 调用 Gemini CLI,并将输出重定向到临时文件,然后读取该文件。
"""
gemini_cmd_path = r'C:\Users\LIPiston\AppData\Roaming\npm\gemini.cmd'
output_tmp_file = 'gemini_output.tmp'
# 为了防止 prompt_text 中的特殊字符(如 ")破坏命令,我们先将其写入一个临时文件
prompt_tmp_file = 'prompt.tmp'
try:
with open(prompt_tmp_file, 'w', encoding='utf-8') as f:
f.write(prompt_text)
# 构建命令
# 使用 type 命令读取 prompt 文件内容,并通过管道传给 gemini cli
command = f'type "{prompt_tmp_file}" | "{gemini_cmd_path}" prompt > "{output_tmp_file}"'
# 执行命令
return_code = os.system(command)
if return_code != 0:
print(f"调用 Gemini CLI 失败,返回码: {return_code}")
# 尝试读取错误输出(如果 gemini cli 将其输出到 stderr,os.system 无法直接捕获)
# 这里我们只能给一个通用提示
if os.path.exists(output_tmp_file):
with open(output_tmp_file, 'r', encoding='utf-8') as f:
error_output = f.read()
if error_output:
print(f"Gemini CLI 可能的输出: {error_output}")
return None
# 读取输出文件
with open(output_tmp_file, 'r', encoding='utf-8') as f:
return f.read().strip()
except Exception as e:
print(f"执行 Gemini CLI 时发生未知错误: {e}")
return None
finally:
# 清理临时文件
if os.path.exists(output_tmp_file):
os.remove(output_tmp_file)
if os.path.exists(prompt_tmp_file):
os.remove(prompt_tmp_file)
def main():
try:
with open('data.json', 'r', encoding='utf-8') as f:
all_repos_by_lang = json.load(f)
except FileNotFoundError:
print("错误:未找到 data.json 文件。请确保您的GitHub star数据已保存到该文件中。")
return
# 将所有语言的仓库合并到一个列表中
all_repos = []
for lang, repos in all_repos_by_lang.items():
all_repos.extend(repos)
chunk_size = 50 # 每个分块处理50个仓库
all_chunks = [all_repos[i:i + chunk_size] for i in range(0, len(all_repos), chunk_size)]
final_markdown = ""
total_chunks = len(all_chunks)
print(f"总共有 {len(all_repos)} 个仓库,将分 {total_chunks} 个批次进行处理...")
# 清空或创建最终的输出文件
with open('classified_stars.md', 'w', encoding='utf-8') as f:
f.write("") # 写入空字符串以清空文件
for i, chunk in enumerate(all_chunks):
print(f"\n--- 正在处理批次 {i + 1}/{total_chunks} ---")
# 为当前分块构建提示语
# 注意:这里我们不再按语言分组,而是让AI对整个列表分类
repo_list_json = json.dumps(chunk, indent=4)
full_prompt = (
PROMPT_GUIDE +
"\n\n请严格按照上述指南对以下GitHub仓库列表进行分类并输出 Markdown 文档。不要添加任何额外的介绍或总结,只需输出分类好的 Markdown 列表:\n" +
"```json\n" + repo_list_json + "\n```"
)
print(f"正在调用 Gemini CLI 处理 {len(chunk)} 个仓库...")
# 调用 Gemini CLI
markdown_output = call_gemini_cli(full_prompt)
if markdown_output:
# 将结果追加到文件
with open('classified_stars.md', 'a', encoding='utf-8') as f:
# 移除可能存在的 ```markdown 包装
if markdown_output.startswith("```markdown"):
markdown_output = markdown_output[len("```markdown"):].strip()
if markdown_output.endswith("```"):
markdown_output = markdown_output[:-len("```")].strip()
f.write(markdown_output + "\n\n")
print(f"批次 {i + 1} 处理完成。")
else:
print(f"批次 {i + 1} 处理失败,跳过此批次。")
continue
print("\n所有批次处理完成!结果已聚合到 classified_stars.md 文件中。")
if __name__ == "__main__":
main()
评论