diff --git a/.sisyphus/reports/tag-100-final-plan.json b/.sisyphus/reports/tag-100-final-plan.json new file mode 100644 index 0000000..d216adf --- /dev/null +++ b/.sisyphus/reports/tag-100-final-plan.json @@ -0,0 +1,615 @@ +{ + "totalTags": 859, + "keepCount": 100, + "dropCount": 759, + "uncoveredProjects": [], + "forcedAdded": [ + { + "id": "cmkqnj1pt0001l504vmrywqeg", + "name": "需要配置", + "projects": 163 + } + ], + "keepTop100": [ + { + "id": "cmk9fpg4h0000kt048l3a2nqu", + "name": "Python", + "nameEn": "Python", + "projects": 268 + }, + { + "id": "cmkqimx520005jx04vyegybp9", + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projects": 213 + }, + { + "id": "cmkqnj1pt0001l504vmrywqeg", + "name": "需要配置", + "nameEn": "Requires Configuration", + "projects": 163 + }, + { + "id": "cmkjjb37v00064j12b84dsrwg", + "name": "TypeScript", + "nameEn": "TypeScript", + "projects": 118 + }, + { + "id": "cmks0yz0h002xl1040w65w47d", + "name": "AI代理", + "nameEn": "AI Agents", + "projects": 52 + }, + { + "id": "cmkql448t0002l504m7bkovze", + "name": "自动化", + "nameEn": "Automation", + "projects": 46 + }, + { + "id": "cmkqjvuo5000ejr04y9ksio48", + "name": "Docker", + "nameEn": "Docker", + "projects": 43 + }, + { + "id": "cmkjjb37v00074j122wpemyas", + "name": "Node.js", + "nameEn": "Node.js", + "projects": 40 + }, + { + "id": "cmkoutfvz0005jr04knetubim", + "name": "JavaScript", + "nameEn": "JavaScript", + "projects": 34 + }, + { + "id": "cmkqklwxm0018jr04zyzlrmlv", + "name": "React", + "nameEn": "React", + "projects": 34 + }, + { + "id": "cmkqjgpzq0002l104qknt9pho", + "name": "开源", + "nameEn": "Open Source", + "projects": 33 + }, + { + "id": "cmkqnvcbg0001jo04us31pcaj", + "name": "低学习成本", + "nameEn": "Low Learning Curve", + "projects": 31 + }, + { + "id": "cmkqk1dbi000ljr045f2rm18m", + "name": "PyTorch", + "nameEn": "PyTorch", + "projects": 30 + }, + { + "id": "cmkrv2jpg0000l204swrx5xh4", + "name": "LangChain", + "nameEn": "LangChain", + "projects": 29 + }, + { + "id": "cmkqlcukz000dl5044c6z8542", + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projects": 28 + }, + { + "id": "cmkqk1dc5000ojr04jq0exq1z", + "name": "大语言模型", + "nameEn": null, + "projects": 25 + }, + { + "id": "cmkqimwxl0000jx04l8q0rdzo", + "name": "LLM", + "nameEn": "LLM", + "projects": 22 + }, + { + "id": "cmks0rbk1002jl104uc7yg2xv", + "name": "Go", + "nameEn": "Go", + "projects": 20 + }, + { + "id": "cmkqm1c6j0003jl04clkn9qyb", + "name": "企业级", + "nameEn": "Enterprise", + "projects": 20 + }, + { + "id": "cmkqnn8hj0006l504j2uedblz", + "name": "需要基础", + "nameEn": "Requires Basics", + "projects": 20 + }, + { + "id": "cmks0yz1e002yl104nw4apfcq", + "name": "Library", + "nameEn": "Library", + "projects": 18 + }, + { + "id": "cmkrx8euz0007ky04hrgq5ryg", + "name": "MCP", + "nameEn": "Model Context Protocol", + "projects": 18 + }, + { + "id": "cmks16lb0003ml104acf4zi7e", + "name": "Markdown", + "nameEn": "Markdown", + "projects": 17 + }, + { + "id": "cmkqklwr20016jr04opezrtpo", + "name": "Next.js", + "nameEn": "Next.js", + "projects": 17 + }, + { + "id": "cmks003y10015l104xruieqo9", + "name": "RAG", + "nameEn": "RAG", + "projects": 17 + }, + { + "id": "cmkqm1bzv0000jl04c3ks3w7w", + "name": "Java", + "nameEn": "Java", + "projects": 16 + }, + { + "id": "cmks0c9ll0022l10436svssah", + "name": "MIT许可", + "nameEn": "MIT License", + "projects": 16 + }, + { + "id": "cmkqnn8gl0005l5042jdeuuur", + "name": "LangGraph", + "nameEn": "LangGraph", + "projects": 15 + }, + { + "id": "cmkrx664z0000ky0481j124cq", + "name": "FastAPI", + "nameEn": "FastAPI", + "projects": 14 + }, + { + "id": "cmkqjvuir0008jr048591dzwp", + "name": "Rust", + "nameEn": "Rust", + "projects": 14 + }, + { + "id": "cmkrzlq020001l104sosii49r", + "name": "复杂部署", + "nameEn": "Complex Deployment", + "projects": 14 + }, + { + "id": "cmkjjb38l000c4j12oucpveph", + "name": "工作流自动化", + "nameEn": "Workflow Automation", + "projects": 14 + }, + { + "id": "cmks3iu8m006wl104ndk8no10", + "name": "C#", + "nameEn": "C#", + "projects": 11 + }, + { + "id": "cmkqnn8mm0007l5045q6z4zb0", + "name": "OpenAI", + "nameEn": "OpenAI", + "projects": 11 + }, + { + "id": "cmkrzvdfk000tl104jsq77zig", + "name": "OpenAI API", + "nameEn": "OpenAI API", + "projects": 11 + }, + { + "id": "cmks3d1wy006ll104gltxc3et", + "name": "SDK", + "nameEn": "SDK", + "projects": 11 + }, + { + "id": "cmks1aoxo003xl104gap1drce", + "name": "强化学习", + "nameEn": "Reinforcement Learning", + "projects": 11 + }, + { + "id": "cmks1aoyn003yl104r4zspprz", + "name": "机器学习", + "nameEn": "Machine Learning", + "projects": 11 + }, + { + "id": "cmksczul60015jv04ft4n1cb2", + "name": "GitHub", + "nameEn": "GitHub", + "projects": 10 + }, + { + "id": "cmks0m380002gl104o6f9cjtj", + "name": "PostgreSQL", + "nameEn": "PostgreSQL", + "projects": 10 + }, + { + "id": "cmkrx8f0j000aky046uomv3rs", + "name": "多模态", + "nameEn": "Multimodal", + "projects": 10 + }, + { + "id": "cmkqjs7e50004jr042mrpi3ac", + "name": "桌面应用", + "nameEn": null, + "projects": 10 + }, + { + "id": "cmkqk4i0d000vjr04ai18b8h3", + "name": "知识管理", + "nameEn": null, + "projects": 10 + }, + { + "id": "cmkqk4i0g000wjr04t82lzvaq", + "name": "向量数据库", + "nameEn": null, + "projects": 9 + }, + { + "id": "cmkrzlq0q0003l10453qhsniu", + "name": "Transformers", + "nameEn": "Transformers", + "projects": 8 + }, + { + "id": "cmks1ubzb004pl104mvs08pmu", + "name": "vLLM", + "nameEn": "vLLM", + "projects": 8 + }, + { + "id": "cmks0eqvq0028l10426ogrvkb", + "name": "云端服务", + "nameEn": "Cloud Service", + "projects": 8 + }, + { + "id": "cmks13z53003el104re4468xt", + "name": "代码生成", + "nameEn": "Code Generation", + "projects": 8 + }, + { + "id": "cmks05ci1001gl104lus7os2q", + "name": "企业级AI应用", + "nameEn": "Enterprise AI", + "projects": 8 + }, + { + "id": "cmks1s7p2004il104kpwprttq", + "name": "智能体框架", + "nameEn": "Agent Framework", + "projects": 8 + }, + { + "id": "cmkqjs7dw0003jr04uy2bguck", + "name": "跨平台", + "nameEn": null, + "projects": 8 + }, + { + "id": "cmkqklwxr0019jr048wp0hds8", + "name": "AI 助手", + "nameEn": "AI Assistant", + "projects": 7 + }, + { + "id": "cmks5ey0j001el204vjk69nwg", + "name": "AI安全", + "nameEn": "AI Security", + "projects": 7 + }, + { + "id": "cmkqjs77s0000jr041cypbjkn", + "name": "Electron", + "nameEn": "Electron", + "projects": 7 + }, + { + "id": "cmkry59tc0001jy04kr21i343", + "name": "Playwright", + "nameEn": "Playwright", + "projects": 7 + }, + { + "id": "cmk9fpg5f0003kt04fcgbvj7y", + "name": "多智能体", + "nameEn": "Multi-Agent", + "projects": 7 + }, + { + "id": "cmkrzxk4i0011l1045cubzwwr", + "name": "深度学习", + "nameEn": "Deep Learning", + "projects": 7 + }, + { + "id": "cmks13z46003dl1047ba0entr", + "name": "AI代理框架", + "nameEn": "AI Agent Framework", + "projects": 6 + }, + { + "id": "cmkry59u70003jy049eoxzkc7", + "name": "AI研究", + "nameEn": "AI Research", + "projects": 6 + }, + { + "id": "cmks2a6r1005il104ormxbqud", + "name": "Web应用", + "nameEn": "Web Application", + "projects": 6 + }, + { + "id": "cmkshrboj0000la04h6bmugvj", + "name": "学术研究", + "nameEn": "Academic Research", + "projects": 6 + }, + { + "id": "cmks112wx0039l104zltcl2hp", + "name": "工作流编排", + "nameEn": "Workflow Orchestration", + "projects": 6 + }, + { + "id": "cmkrzvdfe000sl104q0gge67f", + "name": "教程", + "nameEn": "Tutorial", + "projects": 6 + }, + { + "id": "cmks3w0g0000bl904u4lmk5d5", + "name": "浏览器自动化", + "nameEn": "Browser Automation", + "projects": 6 + }, + { + "id": "cmkt8m55q000nla04kgfld9x3", + "name": "知识图谱", + "nameEn": "Knowledge Graph", + "projects": 6 + }, + { + "id": "cmkqklwxj0017jr04czubkbbi", + "name": "知识库", + "nameEn": "Knowledge Base", + "projects": 6 + }, + { + "id": "cmkshubus0004la04zjuh5nn5", + "name": "自主智能体", + "nameEn": "Autonomous Agents", + "projects": 6 + }, + { + "id": "cmkqk4i0d000ujr045d2njmc7", + "name": "隐私保护", + "nameEn": null, + "projects": 6 + }, + { + "id": "cmks02o6m001al104gi1jztpn", + "name": "Apache-2.0", + "nameEn": "Apache-2.0", + "projects": 5 + }, + { + "id": "cmks4roac000el204paypouzl", + "name": "CLI", + "nameEn": "CLI", + "projects": 5 + }, + { + "id": "cmkt7yhut0000la040ij92vgk", + "name": "MCP协议", + "nameEn": "MCP Protocol", + "projects": 5 + }, + { + "id": "cmks5rr2e0020l204sn9ydvka", + "name": "Nest.js", + "nameEn": "Nest.js", + "projects": 5 + }, + { + "id": "cmkjjb37z00084j121651lnjl", + "name": "Vue.js", + "nameEn": "Vue.js", + "projects": 5 + }, + { + "id": "cmksg1wc90061jv04114izr2d", + "name": "Web自动化", + "nameEn": "Web Automation", + "projects": 5 + }, + { + "id": "cmkuulu5d000jjc04u7hx67sz", + "name": "分布式系统", + "nameEn": "Distributed Systems", + "projects": 5 + }, + { + "id": "cmkqimx3n0001jx043mvrmarx", + "name": "可视化", + "nameEn": "Visualization", + "projects": 5 + }, + { + "id": "cmksf0ik1004ijv047hiusscw", + "name": "多模态AI", + "nameEn": "Multimodal AI", + "projects": 5 + }, + { + "id": "cmktoexz8001wld046f13barg", + "name": "多语言支持", + "nameEn": "Multi-language Support", + "projects": 5 + }, + { + "id": "cmks2gqie005ol104v4d6nvck", + "name": "数据分析", + "nameEn": "Data Analytics", + "projects": 5 + }, + { + "id": "cmks0equs0026l104sl4td34d", + "name": "聊天机器人", + "nameEn": "Chatbot", + "projects": 5 + }, + { + "id": "cmkjjb38j000b4j125a3fg282", + "name": "自托管", + "nameEn": "Self-hosted", + "projects": 5 + }, + { + "id": "cmktkj5to001hl704wtmqjft4", + "name": "自然语言处理", + "nameEn": "Natural Language Processing", + "projects": 5 + }, + { + "id": "cmkrzxk4a0010l104u7irj9je", + "name": "计算机视觉", + "nameEn": "Computer Vision", + "projects": 5 + }, + { + "id": "cmkto2g8o0019ld04b61pgj4y", + "name": "AI研究资源", + "nameEn": "AI Research Resource", + "projects": 4 + }, + { + "id": "cmktk5hid000sl7049a2bo5al", + "name": "Benchmark", + "nameEn": "Benchmark", + "projects": 4 + }, + { + "id": "cmkv6j7uq000gk4043x1gfnp1", + "name": "Bun", + "nameEn": "Bun", + "projects": 4 + }, + { + "id": "cmkti8i470000kz04bpsajkzk", + "name": "ChromaDB", + "nameEn": "ChromaDB", + "projects": 4 + }, + { + "id": "cmks47ct90013l904x03rupwb", + "name": "Flask", + "nameEn": "Flask", + "projects": 4 + }, + { + "id": "cmkql9bho0007l50406oflxr0", + "name": "Gradio", + "nameEn": "Gradio", + "projects": 4 + }, + { + "id": "cmks112qf0034l104gkihwp10", + "name": "JavaScript/TypeScript", + "nameEn": "JavaScript/TypeScript", + "projects": 4 + }, + { + "id": "cmks1s7ut004jl104gvlybgfs", + "name": "LiteLLM", + "nameEn": "LiteLLM", + "projects": 4 + }, + { + "id": "cmks4pb54000bl204erpb9bbp", + "name": "LlamaIndex", + "nameEn": "LlamaIndex", + "projects": 4 + }, + { + "id": "cmksfnrz1005qjv044pnraikr", + "name": "LLM应用", + "nameEn": "LLM Applications", + "projects": 4 + }, + { + "id": "cmkqimx480003jx04bcqob7pb", + "name": "NLP", + "nameEn": "NLP", + "projects": 4 + }, + { + "id": "cmkqm1c690001jl04ge5elv46", + "name": "Spring Boot", + "nameEn": "Spring Boot", + "projects": 4 + }, + { + "id": "cmks2a6l3005gl1040u4s0k4s", + "name": "Streamlit", + "nameEn": "Streamlit", + "projects": 4 + }, + { + "id": "cmkth0k4x0026ju04t0euxxwk", + "name": "VS Code扩展", + "nameEn": "VS Code Extension", + "projects": 4 + }, + { + "id": "cmkscxy490012jv04rf4k4h4h", + "name": "学术资源", + "nameEn": "Academic Resource", + "projects": 4 + }, + { + "id": "cmkscgc0z0007jv04nwmzbn8c", + "name": "工具调用", + "nameEn": "Tool Calling", + "projects": 4 + }, + { + "id": "cmkuxtw0m002ojm04pl9qazxs", + "name": "用户通知", + "nameEn": "User Notification", + "projects": 1 + } + ] +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-100-keep-ids-final.json b/.sisyphus/reports/tag-100-keep-ids-final.json new file mode 100644 index 0000000..1d51619 --- /dev/null +++ b/.sisyphus/reports/tag-100-keep-ids-final.json @@ -0,0 +1,102 @@ +[ + "cmk9fpg4h0000kt048l3a2nqu", + "cmkjjb37v00064j12b84dsrwg", + "cmkqimx520005jx04vyegybp9", + "cmks16lb0003ml104acf4zi7e", + "cmks0yz0h002xl1040w65w47d", + "cmkqjgpzq0002l104qknt9pho", + "cmkql448t0002l504m7bkovze", + "cmkqm1bzv0000jl04c3ks3w7w", + "cmkoutfvz0005jr04knetubim", + "cmks0rbk1002jl104uc7yg2xv", + "cmks3iu8m006wl104ndk8no10", + "cmkqk1dc5000ojr04jq0exq1z", + "cmkqimwxl0000jx04l8q0rdzo", + "cmks0yz1e002yl104nw4apfcq", + "cmkqjvuo5000ejr04y9ksio48", + "cmkjjb37v00074j122wpemyas", + "cmkqnvcbg0001jo04us31pcaj", + "cmkrzlq020001l104sosii49r", + "cmks1aoyn003yl104r4zspprz", + "cmks5ey0j001el204vjk69nwg", + "cmkshrboj0000la04h6bmugvj", + "cmkscgc0z0007jv04nwmzbn8c", + "cmkscxy490012jv04rf4k4h4h", + "cmkuxtw0m002ojm04pl9qazxs", + "cmkqklwxm0018jr04zyzlrmlv", + "cmkqk1dbi000ljr045f2rm18m", + "cmkrv2jpg0000l204swrx5xh4", + "cmkqlcukz000dl5044c6z8542", + "cmkqm1c6j0003jl04clkn9qyb", + "cmkqnn8hj0006l504j2uedblz", + "cmkrx8euz0007ky04hrgq5ryg", + "cmkqklwr20016jr04opezrtpo", + "cmks003y10015l104xruieqo9", + "cmks0c9ll0022l10436svssah", + "cmkqnn8gl0005l5042jdeuuur", + "cmkrx664z0000ky0481j124cq", + "cmkqjvuir0008jr048591dzwp", + "cmkjjb38l000c4j12oucpveph", + "cmkqnn8mm0007l5045q6z4zb0", + "cmkrzvdfk000tl104jsq77zig", + "cmks3d1wy006ll104gltxc3et", + "cmks1aoxo003xl104gap1drce", + "cmksczul60015jv04ft4n1cb2", + "cmks0m380002gl104o6f9cjtj", + "cmkrx8f0j000aky046uomv3rs", + "cmkqjs7e50004jr042mrpi3ac", + "cmkqk4i0d000vjr04ai18b8h3", + "cmkqk4i0g000wjr04t82lzvaq", + "cmkrzlq0q0003l10453qhsniu", + "cmks1ubzb004pl104mvs08pmu", + "cmks0eqvq0028l10426ogrvkb", + "cmks13z53003el104re4468xt", + "cmks05ci1001gl104lus7os2q", + "cmks1s7p2004il104kpwprttq", + "cmkqjs7dw0003jr04uy2bguck", + "cmkqklwxr0019jr048wp0hds8", + "cmkqjs77s0000jr041cypbjkn", + "cmkry59tc0001jy04kr21i343", + "cmk9fpg5f0003kt04fcgbvj7y", + "cmkrzxk4i0011l1045cubzwwr", + "cmks13z46003dl1047ba0entr", + "cmkry59u70003jy049eoxzkc7", + "cmks2a6r1005il104ormxbqud", + "cmks112wx0039l104zltcl2hp", + "cmkrzvdfe000sl104q0gge67f", + "cmks3w0g0000bl904u4lmk5d5", + "cmkt8m55q000nla04kgfld9x3", + "cmkqklwxj0017jr04czubkbbi", + "cmkshubus0004la04zjuh5nn5", + "cmkqk4i0d000ujr045d2njmc7", + "cmks02o6m001al104gi1jztpn", + "cmks4roac000el204paypouzl", + "cmkt7yhut0000la040ij92vgk", + "cmks5rr2e0020l204sn9ydvka", + "cmkjjb37z00084j121651lnjl", + "cmksg1wc90061jv04114izr2d", + "cmkuulu5d000jjc04u7hx67sz", + "cmkqimx3n0001jx043mvrmarx", + "cmksf0ik1004ijv047hiusscw", + "cmktoexz8001wld046f13barg", + "cmks2gqie005ol104v4d6nvck", + "cmks0equs0026l104sl4td34d", + "cmkjjb38j000b4j125a3fg282", + "cmktkj5to001hl704wtmqjft4", + "cmkrzxk4a0010l104u7irj9je", + "cmkto2g8o0019ld04b61pgj4y", + "cmktk5hid000sl7049a2bo5al", + "cmkv6j7uq000gk4043x1gfnp1", + "cmkti8i470000kz04bpsajkzk", + "cmks47ct90013l904x03rupwb", + "cmkql9bho0007l50406oflxr0", + "cmks112qf0034l104gkihwp10", + "cmks1s7ut004jl104gvlybgfs", + "cmks4pb54000bl204erpb9bbp", + "cmksfnrz1005qjv044pnraikr", + "cmkqimx480003jx04bcqob7pb", + "cmkqm1c690001jl04ge5elv46", + "cmks2a6l3005gl1040u4s0k4s", + "cmkth0k4x0026ju04t0euxxwk", + "cmkqnj1pt0001l504vmrywqeg" +] \ No newline at end of file diff --git a/.sisyphus/reports/tag-100-keep-ids.json b/.sisyphus/reports/tag-100-keep-ids.json new file mode 100644 index 0000000..391cecc --- /dev/null +++ b/.sisyphus/reports/tag-100-keep-ids.json @@ -0,0 +1,102 @@ +[ + "cmk9fpg4h0000kt048l3a2nqu", + "cmkqimx520005jx04vyegybp9", + "cmkjjb37v00064j12b84dsrwg", + "cmks0yz0h002xl1040w65w47d", + "cmkql448t0002l504m7bkovze", + "cmkqjvuo5000ejr04y9ksio48", + "cmkjjb37v00074j122wpemyas", + "cmkoutfvz0005jr04knetubim", + "cmkqklwxm0018jr04zyzlrmlv", + "cmkqjgpzq0002l104qknt9pho", + "cmkqnvcbg0001jo04us31pcaj", + "cmkqk1dbi000ljr045f2rm18m", + "cmkrv2jpg0000l204swrx5xh4", + "cmkqlcukz000dl5044c6z8542", + "cmkqk1dc5000ojr04jq0exq1z", + "cmkqimwxl0000jx04l8q0rdzo", + "cmks0rbk1002jl104uc7yg2xv", + "cmkqm1c6j0003jl04clkn9qyb", + "cmkqnn8hj0006l504j2uedblz", + "cmks0yz1e002yl104nw4apfcq", + "cmkrx8euz0007ky04hrgq5ryg", + "cmks16lb0003ml104acf4zi7e", + "cmkqklwr20016jr04opezrtpo", + "cmks003y10015l104xruieqo9", + "cmkqm1bzv0000jl04c3ks3w7w", + "cmks0c9ll0022l10436svssah", + "cmkqnn8gl0005l5042jdeuuur", + "cmkrzlq020001l104sosii49r", + "cmkrx664z0000ky0481j124cq", + "cmkqjvuir0008jr048591dzwp", + "cmkjjb38l000c4j12oucpveph", + "cmks3iu8m006wl104ndk8no10", + "cmks1aoyn003yl104r4zspprz", + "cmkqnn8mm0007l5045q6z4zb0", + "cmkrzvdfk000tl104jsq77zig", + "cmks3d1wy006ll104gltxc3et", + "cmks1aoxo003xl104gap1drce", + "cmksczul60015jv04ft4n1cb2", + "cmks0m380002gl104o6f9cjtj", + "cmkrx8f0j000aky046uomv3rs", + "cmkqjs7e50004jr042mrpi3ac", + "cmkqk4i0d000vjr04ai18b8h3", + "cmkqk4i0g000wjr04t82lzvaq", + "cmkrzlq0q0003l10453qhsniu", + "cmks1ubzb004pl104mvs08pmu", + "cmks0eqvq0028l10426ogrvkb", + "cmks13z53003el104re4468xt", + "cmks05ci1001gl104lus7os2q", + "cmks1s7p2004il104kpwprttq", + "cmkqjs7dw0003jr04uy2bguck", + "cmks5ey0j001el204vjk69nwg", + "cmkqklwxr0019jr048wp0hds8", + "cmkqjs77s0000jr041cypbjkn", + "cmkry59tc0001jy04kr21i343", + "cmk9fpg5f0003kt04fcgbvj7y", + "cmkrzxk4i0011l1045cubzwwr", + "cmkshrboj0000la04h6bmugvj", + "cmks13z46003dl1047ba0entr", + "cmkry59u70003jy049eoxzkc7", + "cmks2a6r1005il104ormxbqud", + "cmks112wx0039l104zltcl2hp", + "cmkrzvdfe000sl104q0gge67f", + "cmks3w0g0000bl904u4lmk5d5", + "cmkt8m55q000nla04kgfld9x3", + "cmkqklwxj0017jr04czubkbbi", + "cmkshubus0004la04zjuh5nn5", + "cmkqk4i0d000ujr045d2njmc7", + "cmks02o6m001al104gi1jztpn", + "cmks4roac000el204paypouzl", + "cmkt7yhut0000la040ij92vgk", + "cmks5rr2e0020l204sn9ydvka", + "cmkjjb37z00084j121651lnjl", + "cmksg1wc90061jv04114izr2d", + "cmkuulu5d000jjc04u7hx67sz", + "cmkqimx3n0001jx043mvrmarx", + "cmksf0ik1004ijv047hiusscw", + "cmktoexz8001wld046f13barg", + "cmks2gqie005ol104v4d6nvck", + "cmks0equs0026l104sl4td34d", + "cmkjjb38j000b4j125a3fg282", + "cmktkj5to001hl704wtmqjft4", + "cmkrzxk4a0010l104u7irj9je", + "cmkscgc0z0007jv04nwmzbn8c", + "cmkscxy490012jv04rf4k4h4h", + "cmkto2g8o0019ld04b61pgj4y", + "cmktk5hid000sl7049a2bo5al", + "cmkv6j7uq000gk4043x1gfnp1", + "cmkti8i470000kz04bpsajkzk", + "cmks47ct90013l904x03rupwb", + "cmkql9bho0007l50406oflxr0", + "cmks112qf0034l104gkihwp10", + "cmks1s7ut004jl104gvlybgfs", + "cmks4pb54000bl204erpb9bbp", + "cmksfnrz1005qjv044pnraikr", + "cmkqimx480003jx04bcqob7pb", + "cmkqm1c690001jl04ge5elv46", + "cmks2a6l3005gl1040u4s0k4s", + "cmkth0k4x0026ju04t0euxxwk", + "cmkuuqo3g000njc04l72uwte3", + "cmkuxtw0m002ojm04pl9qazxs" +] \ No newline at end of file diff --git a/.sisyphus/reports/tag-100-plan-preview.json b/.sisyphus/reports/tag-100-plan-preview.json new file mode 100644 index 0000000..5ce63d1 --- /dev/null +++ b/.sisyphus/reports/tag-100-plan-preview.json @@ -0,0 +1,784 @@ +{ + "totalTags": 859, + "candidatesAfterGenericFilter": 831, + "selectedCount": 100, + "selectedProjectsCoverage": { + "coveredProjects": 453, + "totalProjects": 454, + "coverageRatio": 0.9978, + "uncoveredProjects": 1 + }, + "dropCount": 759, + "topSelected": [ + { + "id": "cmk9fpg4h0000kt048l3a2nqu", + "name": "Python", + "nameEn": "Python", + "projects": 268 + }, + { + "id": "cmkqimx520005jx04vyegybp9", + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projects": 213 + }, + { + "id": "cmkjjb37v00064j12b84dsrwg", + "name": "TypeScript", + "nameEn": "TypeScript", + "projects": 118 + }, + { + "id": "cmks0yz0h002xl1040w65w47d", + "name": "AI代理", + "nameEn": "AI Agents", + "projects": 52 + }, + { + "id": "cmkql448t0002l504m7bkovze", + "name": "自动化", + "nameEn": "Automation", + "projects": 46 + }, + { + "id": "cmkqjvuo5000ejr04y9ksio48", + "name": "Docker", + "nameEn": "Docker", + "projects": 43 + }, + { + "id": "cmkjjb37v00074j122wpemyas", + "name": "Node.js", + "nameEn": "Node.js", + "projects": 40 + }, + { + "id": "cmkoutfvz0005jr04knetubim", + "name": "JavaScript", + "nameEn": "JavaScript", + "projects": 34 + }, + { + "id": "cmkqklwxm0018jr04zyzlrmlv", + "name": "React", + "nameEn": "React", + "projects": 34 + }, + { + "id": "cmkqjgpzq0002l104qknt9pho", + "name": "开源", + "nameEn": "Open Source", + "projects": 33 + }, + { + "id": "cmkqnvcbg0001jo04us31pcaj", + "name": "低学习成本", + "nameEn": "Low Learning Curve", + "projects": 31 + }, + { + "id": "cmkqk1dbi000ljr045f2rm18m", + "name": "PyTorch", + "nameEn": "PyTorch", + "projects": 30 + }, + { + "id": "cmkrv2jpg0000l204swrx5xh4", + "name": "LangChain", + "nameEn": "LangChain", + "projects": 29 + }, + { + "id": "cmkqlcukz000dl5044c6z8542", + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projects": 28 + }, + { + "id": "cmkqk1dc5000ojr04jq0exq1z", + "name": "大语言模型", + "nameEn": null, + "projects": 25 + }, + { + "id": "cmkqimwxl0000jx04l8q0rdzo", + "name": "LLM", + "nameEn": "LLM", + "projects": 22 + }, + { + "id": "cmks0rbk1002jl104uc7yg2xv", + "name": "Go", + "nameEn": "Go", + "projects": 20 + }, + { + "id": "cmkqm1c6j0003jl04clkn9qyb", + "name": "企业级", + "nameEn": "Enterprise", + "projects": 20 + }, + { + "id": "cmkqnn8hj0006l504j2uedblz", + "name": "需要基础", + "nameEn": "Requires Basics", + "projects": 20 + }, + { + "id": "cmks0yz1e002yl104nw4apfcq", + "name": "Library", + "nameEn": "Library", + "projects": 18 + }, + { + "id": "cmkrx8euz0007ky04hrgq5ryg", + "name": "MCP", + "nameEn": "Model Context Protocol", + "projects": 18 + }, + { + "id": "cmks16lb0003ml104acf4zi7e", + "name": "Markdown", + "nameEn": "Markdown", + "projects": 17 + }, + { + "id": "cmkqklwr20016jr04opezrtpo", + "name": "Next.js", + "nameEn": "Next.js", + "projects": 17 + }, + { + "id": "cmks003y10015l104xruieqo9", + "name": "RAG", + "nameEn": "RAG", + "projects": 17 + }, + { + "id": "cmkqm1bzv0000jl04c3ks3w7w", + "name": "Java", + "nameEn": "Java", + "projects": 16 + }, + { + "id": "cmks0c9ll0022l10436svssah", + "name": "MIT许可", + "nameEn": "MIT License", + "projects": 16 + }, + { + "id": "cmkqnn8gl0005l5042jdeuuur", + "name": "LangGraph", + "nameEn": "LangGraph", + "projects": 15 + }, + { + "id": "cmkrzlq020001l104sosii49r", + "name": "复杂部署", + "nameEn": "Complex Deployment", + "projects": 14 + }, + { + "id": "cmkrx664z0000ky0481j124cq", + "name": "FastAPI", + "nameEn": "FastAPI", + "projects": 14 + }, + { + "id": "cmkqjvuir0008jr048591dzwp", + "name": "Rust", + "nameEn": "Rust", + "projects": 14 + }, + { + "id": "cmkjjb38l000c4j12oucpveph", + "name": "工作流自动化", + "nameEn": "Workflow Automation", + "projects": 14 + }, + { + "id": "cmks3iu8m006wl104ndk8no10", + "name": "C#", + "nameEn": "C#", + "projects": 11 + }, + { + "id": "cmks1aoyn003yl104r4zspprz", + "name": "机器学习", + "nameEn": "Machine Learning", + "projects": 11 + }, + { + "id": "cmkqnn8mm0007l5045q6z4zb0", + "name": "OpenAI", + "nameEn": "OpenAI", + "projects": 11 + }, + { + "id": "cmkrzvdfk000tl104jsq77zig", + "name": "OpenAI API", + "nameEn": "OpenAI API", + "projects": 11 + }, + { + "id": "cmks3d1wy006ll104gltxc3et", + "name": "SDK", + "nameEn": "SDK", + "projects": 11 + }, + { + "id": "cmks1aoxo003xl104gap1drce", + "name": "强化学习", + "nameEn": "Reinforcement Learning", + "projects": 11 + }, + { + "id": "cmksczul60015jv04ft4n1cb2", + "name": "GitHub", + "nameEn": "GitHub", + "projects": 10 + }, + { + "id": "cmks0m380002gl104o6f9cjtj", + "name": "PostgreSQL", + "nameEn": "PostgreSQL", + "projects": 10 + }, + { + "id": "cmkrx8f0j000aky046uomv3rs", + "name": "多模态", + "nameEn": "Multimodal", + "projects": 10 + }, + { + "id": "cmkqjs7e50004jr042mrpi3ac", + "name": "桌面应用", + "nameEn": null, + "projects": 10 + }, + { + "id": "cmkqk4i0d000vjr04ai18b8h3", + "name": "知识管理", + "nameEn": null, + "projects": 10 + }, + { + "id": "cmkqk4i0g000wjr04t82lzvaq", + "name": "向量数据库", + "nameEn": null, + "projects": 9 + }, + { + "id": "cmkrzlq0q0003l10453qhsniu", + "name": "Transformers", + "nameEn": "Transformers", + "projects": 8 + }, + { + "id": "cmks1ubzb004pl104mvs08pmu", + "name": "vLLM", + "nameEn": "vLLM", + "projects": 8 + }, + { + "id": "cmks0eqvq0028l10426ogrvkb", + "name": "云端服务", + "nameEn": "Cloud Service", + "projects": 8 + }, + { + "id": "cmks13z53003el104re4468xt", + "name": "代码生成", + "nameEn": "Code Generation", + "projects": 8 + }, + { + "id": "cmks05ci1001gl104lus7os2q", + "name": "企业级AI应用", + "nameEn": "Enterprise AI", + "projects": 8 + }, + { + "id": "cmks1s7p2004il104kpwprttq", + "name": "智能体框架", + "nameEn": "Agent Framework", + "projects": 8 + }, + { + "id": "cmkqjs7dw0003jr04uy2bguck", + "name": "跨平台", + "nameEn": null, + "projects": 8 + }, + { + "id": "cmks5ey0j001el204vjk69nwg", + "name": "AI安全", + "nameEn": "AI Security", + "projects": 7 + }, + { + "id": "cmkqklwxr0019jr048wp0hds8", + "name": "AI 助手", + "nameEn": "AI Assistant", + "projects": 7 + }, + { + "id": "cmkqjs77s0000jr041cypbjkn", + "name": "Electron", + "nameEn": "Electron", + "projects": 7 + }, + { + "id": "cmkry59tc0001jy04kr21i343", + "name": "Playwright", + "nameEn": "Playwright", + "projects": 7 + }, + { + "id": "cmk9fpg5f0003kt04fcgbvj7y", + "name": "多智能体", + "nameEn": "Multi-Agent", + "projects": 7 + }, + { + "id": "cmkrzxk4i0011l1045cubzwwr", + "name": "深度学习", + "nameEn": "Deep Learning", + "projects": 7 + }, + { + "id": "cmkshrboj0000la04h6bmugvj", + "name": "学术研究", + "nameEn": "Academic Research", + "projects": 6 + }, + { + "id": "cmks13z46003dl1047ba0entr", + "name": "AI代理框架", + "nameEn": "AI Agent Framework", + "projects": 6 + }, + { + "id": "cmkry59u70003jy049eoxzkc7", + "name": "AI研究", + "nameEn": "AI Research", + "projects": 6 + }, + { + "id": "cmks2a6r1005il104ormxbqud", + "name": "Web应用", + "nameEn": "Web Application", + "projects": 6 + }, + { + "id": "cmks112wx0039l104zltcl2hp", + "name": "工作流编排", + "nameEn": "Workflow Orchestration", + "projects": 6 + }, + { + "id": "cmkrzvdfe000sl104q0gge67f", + "name": "教程", + "nameEn": "Tutorial", + "projects": 6 + }, + { + "id": "cmks3w0g0000bl904u4lmk5d5", + "name": "浏览器自动化", + "nameEn": "Browser Automation", + "projects": 6 + }, + { + "id": "cmkt8m55q000nla04kgfld9x3", + "name": "知识图谱", + "nameEn": "Knowledge Graph", + "projects": 6 + }, + { + "id": "cmkqklwxj0017jr04czubkbbi", + "name": "知识库", + "nameEn": "Knowledge Base", + "projects": 6 + }, + { + "id": "cmkshubus0004la04zjuh5nn5", + "name": "自主智能体", + "nameEn": "Autonomous Agents", + "projects": 6 + }, + { + "id": "cmkqk4i0d000ujr045d2njmc7", + "name": "隐私保护", + "nameEn": null, + "projects": 6 + }, + { + "id": "cmks02o6m001al104gi1jztpn", + "name": "Apache-2.0", + "nameEn": "Apache-2.0", + "projects": 5 + }, + { + "id": "cmks4roac000el204paypouzl", + "name": "CLI", + "nameEn": "CLI", + "projects": 5 + }, + { + "id": "cmkt7yhut0000la040ij92vgk", + "name": "MCP协议", + "nameEn": "MCP Protocol", + "projects": 5 + }, + { + "id": "cmks5rr2e0020l204sn9ydvka", + "name": "Nest.js", + "nameEn": "Nest.js", + "projects": 5 + }, + { + "id": "cmkjjb37z00084j121651lnjl", + "name": "Vue.js", + "nameEn": "Vue.js", + "projects": 5 + }, + { + "id": "cmksg1wc90061jv04114izr2d", + "name": "Web自动化", + "nameEn": "Web Automation", + "projects": 5 + }, + { + "id": "cmkuulu5d000jjc04u7hx67sz", + "name": "分布式系统", + "nameEn": "Distributed Systems", + "projects": 5 + }, + { + "id": "cmkqimx3n0001jx043mvrmarx", + "name": "可视化", + "nameEn": "Visualization", + "projects": 5 + }, + { + "id": "cmksf0ik1004ijv047hiusscw", + "name": "多模态AI", + "nameEn": "Multimodal AI", + "projects": 5 + }, + { + "id": "cmktoexz8001wld046f13barg", + "name": "多语言支持", + "nameEn": "Multi-language Support", + "projects": 5 + }, + { + "id": "cmks2gqie005ol104v4d6nvck", + "name": "数据分析", + "nameEn": "Data Analytics", + "projects": 5 + }, + { + "id": "cmks0equs0026l104sl4td34d", + "name": "聊天机器人", + "nameEn": "Chatbot", + "projects": 5 + }, + { + "id": "cmkjjb38j000b4j125a3fg282", + "name": "自托管", + "nameEn": "Self-hosted", + "projects": 5 + }, + { + "id": "cmktkj5to001hl704wtmqjft4", + "name": "自然语言处理", + "nameEn": "Natural Language Processing", + "projects": 5 + }, + { + "id": "cmkrzxk4a0010l104u7irj9je", + "name": "计算机视觉", + "nameEn": "Computer Vision", + "projects": 5 + }, + { + "id": "cmkscgc0z0007jv04nwmzbn8c", + "name": "工具调用", + "nameEn": "Tool Calling", + "projects": 4 + }, + { + "id": "cmkscxy490012jv04rf4k4h4h", + "name": "学术资源", + "nameEn": "Academic Resource", + "projects": 4 + }, + { + "id": "cmkto2g8o0019ld04b61pgj4y", + "name": "AI研究资源", + "nameEn": "AI Research Resource", + "projects": 4 + }, + { + "id": "cmktk5hid000sl7049a2bo5al", + "name": "Benchmark", + "nameEn": "Benchmark", + "projects": 4 + }, + { + "id": "cmkv6j7uq000gk4043x1gfnp1", + "name": "Bun", + "nameEn": "Bun", + "projects": 4 + }, + { + "id": "cmkti8i470000kz04bpsajkzk", + "name": "ChromaDB", + "nameEn": "ChromaDB", + "projects": 4 + }, + { + "id": "cmks47ct90013l904x03rupwb", + "name": "Flask", + "nameEn": "Flask", + "projects": 4 + }, + { + "id": "cmkql9bho0007l50406oflxr0", + "name": "Gradio", + "nameEn": "Gradio", + "projects": 4 + }, + { + "id": "cmks112qf0034l104gkihwp10", + "name": "JavaScript/TypeScript", + "nameEn": "JavaScript/TypeScript", + "projects": 4 + }, + { + "id": "cmks1s7ut004jl104gvlybgfs", + "name": "LiteLLM", + "nameEn": "LiteLLM", + "projects": 4 + }, + { + "id": "cmks4pb54000bl204erpb9bbp", + "name": "LlamaIndex", + "nameEn": "LlamaIndex", + "projects": 4 + }, + { + "id": "cmksfnrz1005qjv044pnraikr", + "name": "LLM应用", + "nameEn": "LLM Applications", + "projects": 4 + }, + { + "id": "cmkqimx480003jx04bcqob7pb", + "name": "NLP", + "nameEn": "NLP", + "projects": 4 + }, + { + "id": "cmkqm1c690001jl04ge5elv46", + "name": "Spring Boot", + "nameEn": "Spring Boot", + "projects": 4 + }, + { + "id": "cmks2a6l3005gl1040u4s0k4s", + "name": "Streamlit", + "nameEn": "Streamlit", + "projects": 4 + }, + { + "id": "cmkth0k4x0026ju04t0euxxwk", + "name": "VS Code扩展", + "nameEn": "VS Code Extension", + "projects": 4 + }, + { + "id": "cmkuuqo3g000njc04l72uwte3", + "name": "文件系统操作", + "nameEn": "File System Operations", + "projects": 2 + }, + { + "id": "cmkuxtw0m002ojm04pl9qazxs", + "name": "用户通知", + "nameEn": "User Notification", + "projects": 1 + } + ], + "genericRemovedTop": [ + { + "id": "cmkoutfta0001jr04qlwpr3xh", + "name": "活跃维护", + "nameEn": "Active Maintenance", + "projects": 317 + }, + { + "id": "cmkqk1dbs000njr0418v38jh4", + "name": "可商用", + "nameEn": null, + "projects": 171 + }, + { + "id": "cmkqnj1pt0001l504vmrywqeg", + "name": "需要配置", + "nameEn": "Requires Configuration", + "projects": 163 + }, + { + "id": "cmkqk1div000qjr04ckie91k5", + "name": "AI", + "nameEn": "AI", + "projects": 115 + }, + { + "id": "cmkoutfub0004jr049qn5fxc0", + "name": "易上手", + "nameEn": "Easy to Start", + "projects": 107 + }, + { + "id": "cmkoutftj0002jr04xqiuu0cb", + "name": "框架", + "nameEn": "Framework", + "projects": 90 + }, + { + "id": "cmkqk1d5o000kjr049wqf7i5o", + "name": "开发工具", + "nameEn": null, + "projects": 88 + }, + { + "id": "cmkqnvc540000jo04qrexxuhd", + "name": "开箱即用", + "nameEn": "Ready to Use", + "projects": 72 + }, + { + "id": "cmkqkapuh0010jr043s59my3y", + "name": "文档完善", + "nameEn": "Well Documented", + "projects": 69 + }, + { + "id": "cmkqk4i0g000xjr04sn06e7wt", + "name": "本地部署", + "nameEn": null, + "projects": 38 + }, + { + "id": "cmkoutfu10003jr04dw11uzvu", + "name": "有示例", + "nameEn": "Has Examples", + "projects": 36 + }, + { + "id": "cmkql442c0000l504qbomadup", + "name": "需要Docker", + "nameEn": "Requires Docker", + "projects": 36 + }, + { + "id": "cmkryxmob0003l80414uo5zqz", + "name": "CLI工具", + "nameEn": "CLI Tool", + "projects": 33 + }, + { + "id": "cmks1fjqc0042l104cqi0dh9v", + "name": "工具", + "nameEn": "Tool", + "projects": 33 + }, + { + "id": "cmkqkaq140011jr04n5aqr763", + "name": "平台", + "nameEn": "Platform", + "projects": 29 + }, + { + "id": "cmkrzlq0e0002l104jfnarvv8", + "name": "智能体", + "nameEn": "Agent", + "projects": 16 + }, + { + "id": "cmk9fpg560001kt04ab5369hg", + "name": "开发框架", + "nameEn": "Development Framework", + "projects": 10 + }, + { + "id": "cmk9fpg580002kt04sslxarl5", + "name": "人工智能", + "nameEn": "Artificial Intelligence", + "projects": 7 + }, + { + "id": "cmkrv2jvc0001l204703u5836", + "name": "开发者工具", + "nameEn": "Developer Tool", + "projects": 4 + }, + { + "id": "cmksdlj9o0029jv04x9tdyc11", + "name": "科研工具", + "nameEn": "Research Tool", + "projects": 4 + }, + { + "id": "cmks4tb3k000jl204z6oxfuyh", + "name": "终端工具", + "nameEn": "Terminal Tools", + "projects": 4 + }, + { + "id": "cmkqjgpzv0003l104asyyc6dg", + "name": "低代码平台", + "nameEn": "Low-Code Platform", + "projects": 3 + }, + { + "id": "cmkrxh1kc000hky04rpxvrj1w", + "name": "数据库工具", + "nameEn": "Database Tools", + "projects": 3 + }, + { + "id": "cmks05cng001il1049zztjibt", + "name": "Agent平台", + "nameEn": "Agent Platform", + "projects": 3 + }, + { + "id": "cmkjjb38300094j12lum5vwjj", + "name": "集成平台", + "nameEn": "Integration Platform", + "projects": 2 + }, + { + "id": "cmkt8ex6g000ala0488t486bj", + "name": "平台/框架", + "nameEn": "Platform/Framework", + "projects": 1 + }, + { + "id": "cmktpw9pe003tld04fjjgo4zt", + "name": "系统监控", + "nameEn": "System Monitoring", + "projects": 1 + }, + { + "id": "cmkuxtvzn002mjm04wdcx9wwi", + "name": "系统通知", + "nameEn": "System Notification", + "projects": 1 + } + ] +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-audit-before-100-cap.json b/.sisyphus/reports/tag-audit-before-100-cap.json new file mode 100644 index 0000000..33a8875 --- /dev/null +++ b/.sisyphus/reports/tag-audit-before-100-cap.json @@ -0,0 +1,305 @@ +{ + "totalTags": 859, + "totalProjects": 454, + "activeProjects": 444, + "distributionAtLeast": { + "1": 859, + "2": 283, + "3": 169, + "4": 130, + "5": 100, + "6": 85, + "8": 67, + "10": 59, + "15": 43, + "20": 34, + "30": 26, + "50": 13 + }, + "top100CoverageProjects": 453, + "projectsWithoutTop100Tag": 1, + "top20": [ + { + "name": "活跃维护", + "nameEn": "Active Maintenance", + "projects": 317 + }, + { + "name": "Python", + "nameEn": "Python", + "projects": 268 + }, + { + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projects": 213 + }, + { + "name": "可商用", + "nameEn": null, + "projects": 171 + }, + { + "name": "需要配置", + "nameEn": "Requires Configuration", + "projects": 163 + }, + { + "name": "TypeScript", + "nameEn": "TypeScript", + "projects": 118 + }, + { + "name": "AI", + "nameEn": "AI", + "projects": 115 + }, + { + "name": "易上手", + "nameEn": "Easy to Start", + "projects": 107 + }, + { + "name": "框架", + "nameEn": "Framework", + "projects": 90 + }, + { + "name": "开发工具", + "nameEn": null, + "projects": 88 + }, + { + "name": "开箱即用", + "nameEn": "Ready to Use", + "projects": 72 + }, + { + "name": "文档完善", + "nameEn": "Well Documented", + "projects": 69 + }, + { + "name": "AI代理", + "nameEn": "AI Agents", + "projects": 52 + }, + { + "name": "自动化", + "nameEn": "Automation", + "projects": 46 + }, + { + "name": "Docker", + "nameEn": "Docker", + "projects": 43 + }, + { + "name": "Node.js", + "nameEn": "Node.js", + "projects": 40 + }, + { + "name": "本地部署", + "nameEn": null, + "projects": 38 + }, + { + "name": "有示例", + "nameEn": "Has Examples", + "projects": 36 + }, + { + "name": "需要Docker", + "nameEn": "Requires Docker", + "projects": 36 + }, + { + "name": "JavaScript", + "nameEn": "JavaScript", + "projects": 34 + } + ], + "genericTagsTop30": [ + { + "id": "cmkqimx520005jx04vyegybp9", + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projects": 213 + }, + { + "id": "cmkqk1div000qjr04ckie91k5", + "name": "AI", + "nameEn": "AI", + "projects": 115 + }, + { + "id": "cmkoutftj0002jr04xqiuu0cb", + "name": "框架", + "nameEn": "Framework", + "projects": 90 + }, + { + "id": "cmkqk1d5o000kjr049wqf7i5o", + "name": "开发工具", + "nameEn": null, + "projects": 88 + }, + { + "id": "cmks0yz0h002xl1040w65w47d", + "name": "AI代理", + "nameEn": "AI Agents", + "projects": 52 + }, + { + "id": "cmkryxmob0003l80414uo5zqz", + "name": "CLI工具", + "nameEn": "CLI Tool", + "projects": 33 + }, + { + "id": "cmks1fjqc0042l104cqi0dh9v", + "name": "工具", + "nameEn": "Tool", + "projects": 33 + }, + { + "id": "cmkqkaq140011jr04n5aqr763", + "name": "平台", + "nameEn": "Platform", + "projects": 29 + }, + { + "id": "cmkqlcukz000dl5044c6z8542", + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projects": 28 + }, + { + "id": "cmkrzlq0e0002l104jfnarvv8", + "name": "智能体", + "nameEn": "Agent", + "projects": 16 + }, + { + "id": "cmk9fpg560001kt04ab5369hg", + "name": "开发框架", + "nameEn": "Development Framework", + "projects": 10 + }, + { + "id": "cmks05ci1001gl104lus7os2q", + "name": "企业级AI应用", + "nameEn": "Enterprise AI", + "projects": 8 + }, + { + "id": "cmks1s7p2004il104kpwprttq", + "name": "智能体框架", + "nameEn": "Agent Framework", + "projects": 8 + }, + { + "id": "cmk9fpg580002kt04sslxarl5", + "name": "人工智能", + "nameEn": "Artificial Intelligence", + "projects": 7 + }, + { + "id": "cmk9fpg5f0003kt04fcgbvj7y", + "name": "多智能体", + "nameEn": "Multi-Agent", + "projects": 7 + }, + { + "id": "cmkqklwxr0019jr048wp0hds8", + "name": "AI 助手", + "nameEn": "AI Assistant", + "projects": 7 + }, + { + "id": "cmkshubus0004la04zjuh5nn5", + "name": "自主智能体", + "nameEn": "Autonomous Agents", + "projects": 6 + }, + { + "id": "cmks13z46003dl1047ba0entr", + "name": "AI代理框架", + "nameEn": "AI Agent Framework", + "projects": 6 + }, + { + "id": "cmksf0ik1004ijv047hiusscw", + "name": "多模态AI", + "nameEn": "Multimodal AI", + "projects": 5 + }, + { + "id": "cmkrv2jvc0001l204703u5836", + "name": "开发者工具", + "nameEn": "Developer Tool", + "projects": 4 + }, + { + "id": "cmksdlj9o0029jv04x9tdyc11", + "name": "科研工具", + "nameEn": "Research Tool", + "projects": 4 + }, + { + "id": "cmksf2ncg004pjv0446rsr0e6", + "name": "生成式AI", + "nameEn": "Generative AI", + "projects": 4 + }, + { + "id": "cmks4tb3k000jl204z6oxfuyh", + "name": "终端工具", + "nameEn": "Terminal Tools", + "projects": 4 + }, + { + "id": "cmkqjgpzv0003l104asyyc6dg", + "name": "低代码平台", + "nameEn": "Low-Code Platform", + "projects": 3 + }, + { + "id": "cmkqlcuqx000fl504ywms66me", + "name": "AI开发框架", + "nameEn": "AI Development Framework", + "projects": 3 + }, + { + "id": "cmkujqy2l0007jx04w5zxt8be", + "name": "游戏AI", + "nameEn": "Game AI", + "projects": 3 + }, + { + "id": "cmkrxh1kc000hky04rpxvrj1w", + "name": "数据库工具", + "nameEn": "Database Tools", + "projects": 3 + }, + { + "id": "cmks05cng001il1049zztjibt", + "name": "Agent平台", + "nameEn": "Agent Platform", + "projects": 3 + }, + { + "id": "cmks3y6z0000hl9048h3bv62n", + "name": "记忆系统", + "nameEn": "Memory System", + "projects": 3 + }, + { + "id": "cmkjjb38300094j12lum5vwjj", + "name": "集成平台", + "nameEn": "Integration Platform", + "projects": 2 + } + ] +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-cap-100-result-2026-02-21.json b/.sisyphus/reports/tag-cap-100-result-2026-02-21.json new file mode 100644 index 0000000..5e1c07f --- /dev/null +++ b/.sisyphus/reports/tag-cap-100-result-2026-02-21.json @@ -0,0 +1,163 @@ +{ + "totalTags": 100, + "totalProjectTags": 1888, + "zeroTags": 0, + "aiTagExists": false, + "aiTag": null, + "projectCoverage": { + "covered": 454, + "total": 454 + }, + "top30": [ + { + "name": "Python", + "nameEn": "Python", + "projects": 268 + }, + { + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projects": 213 + }, + { + "name": "需要配置", + "nameEn": "Requires Configuration", + "projects": 163 + }, + { + "name": "TypeScript", + "nameEn": "TypeScript", + "projects": 118 + }, + { + "name": "AI代理", + "nameEn": "AI Agents", + "projects": 52 + }, + { + "name": "自动化", + "nameEn": "Automation", + "projects": 46 + }, + { + "name": "Docker", + "nameEn": "Docker", + "projects": 43 + }, + { + "name": "Node.js", + "nameEn": "Node.js", + "projects": 40 + }, + { + "name": "JavaScript", + "nameEn": "JavaScript", + "projects": 34 + }, + { + "name": "React", + "nameEn": "React", + "projects": 34 + }, + { + "name": "开源", + "nameEn": "Open Source", + "projects": 33 + }, + { + "name": "低学习成本", + "nameEn": "Low Learning Curve", + "projects": 31 + }, + { + "name": "PyTorch", + "nameEn": "PyTorch", + "projects": 30 + }, + { + "name": "LangChain", + "nameEn": "LangChain", + "projects": 29 + }, + { + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projects": 28 + }, + { + "name": "大语言模型", + "nameEn": null, + "projects": 25 + }, + { + "name": "LLM", + "nameEn": "LLM", + "projects": 22 + }, + { + "name": "Go", + "nameEn": "Go", + "projects": 20 + }, + { + "name": "企业级", + "nameEn": "Enterprise", + "projects": 20 + }, + { + "name": "需要基础", + "nameEn": "Requires Basics", + "projects": 20 + }, + { + "name": "Library", + "nameEn": "Library", + "projects": 18 + }, + { + "name": "MCP", + "nameEn": "Model Context Protocol", + "projects": 18 + }, + { + "name": "Markdown", + "nameEn": "Markdown", + "projects": 17 + }, + { + "name": "Next.js", + "nameEn": "Next.js", + "projects": 17 + }, + { + "name": "RAG", + "nameEn": "RAG", + "projects": 17 + }, + { + "name": "Java", + "nameEn": "Java", + "projects": 16 + }, + { + "name": "MIT许可", + "nameEn": "MIT License", + "projects": 16 + }, + { + "name": "LangGraph", + "nameEn": "LangGraph", + "projects": 15 + }, + { + "name": "FastAPI", + "nameEn": "FastAPI", + "projects": 14 + }, + { + "name": "Rust", + "nameEn": "Rust", + "projects": 14 + } + ] +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-cleanup-plan-2026-02-21.json b/.sisyphus/reports/tag-cleanup-plan-2026-02-21.json new file mode 100644 index 0000000..0458abc --- /dev/null +++ b/.sisyphus/reports/tag-cleanup-plan-2026-02-21.json @@ -0,0 +1,44 @@ +{ + "generatedAt": "2026-02-21T03:47:31.204Z", + "mergeGroupCount": 6, + "mergePairCount": 6, + "mergePairs": [ + { + "sourceId": "cmkoutg0o0006jr04goozjhft", + "targetId": "cmkqimx520005jx04vyegybp9", + "key": "ai development tool" + }, + { + "sourceId": "cmkjjb387000a4j12pdf123zn", + "targetId": "cmks0yz0h002xl1040w65w47d", + "key": "ai agent" + }, + { + "sourceId": "cmkun0ao70048jx04atm2lwwq", + "targetId": "cmkryxmob0003l80414uo5zqz", + "key": "cli tool" + }, + { + "sourceId": "cmkrzqdlu000fl104qmy9gu2u", + "targetId": "cmkqlcukz000dl5044c6z8542", + "key": "multi agent system" + }, + { + "sourceId": "cmktk3biu000nl704iiohmv4i", + "targetId": "cmksdlj9o0029jv04x9tdyc11", + "key": "research tool" + }, + { + "sourceId": "cmktpotkp003eld04mv09ckde", + "targetId": "cmkshubus0004la04zjuh5nn5", + "key": "autonomous agent" + } + ], + "before": { + "totalTags": 955, + "totalProjectTags": 4131, + "zeroTags": 90, + "missingNameEnAscii": null + }, + "sqlPath": ".sisyphus/sql/tag-cleanup-2026-02-21.sql" +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-cleanup-result-2026-02-21.json b/.sisyphus/reports/tag-cleanup-result-2026-02-21.json new file mode 100644 index 0000000..9945dc7 --- /dev/null +++ b/.sisyphus/reports/tag-cleanup-result-2026-02-21.json @@ -0,0 +1,42 @@ +{ + "after": { + "totalTags": 859, + "totalProjectTags": 4131, + "zeroTags": 0, + "missingNameEn": 17, + "missingNameEnAscii": 0 + }, + "deletedSourceTagsStillExists": [], + "mergedTargetProjectCounts": [ + { + "id": "cmkshubus0004la04zjuh5nn5", + "name": "自主智能体", + "projects": 6 + }, + { + "id": "cmkryxmob0003l80414uo5zqz", + "name": "CLI工具", + "projects": 33 + }, + { + "id": "cmkqlcukz000dl5044c6z8542", + "name": "多智能体系统", + "projects": 28 + }, + { + "id": "cmkqimx520005jx04vyegybp9", + "name": "AI开发工具", + "projects": 213 + }, + { + "id": "cmks0yz0h002xl1040w65w47d", + "name": "AI代理", + "projects": 52 + }, + { + "id": "cmksdlj9o0029jv04x9tdyc11", + "name": "科研工具", + "projects": 4 + } + ] +} \ No newline at end of file diff --git a/.sisyphus/reports/tag-current-100-full.json b/.sisyphus/reports/tag-current-100-full.json new file mode 100644 index 0000000..fd4f045 --- /dev/null +++ b/.sisyphus/reports/tag-current-100-full.json @@ -0,0 +1,1002 @@ +[ + { + "id": "cmk9fpg4h0000kt048l3a2nqu", + "name": "Python", + "nameEn": "Python", + "slug": "python", + "_count": { + "projects": 268 + }, + "projectCount": 268 + }, + { + "id": "cmkqimx520005jx04vyegybp9", + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "slug": "ai-development-tool", + "_count": { + "projects": 213 + }, + "projectCount": 213 + }, + { + "id": "cmkqnj1pt0001l504vmrywqeg", + "name": "需要配置", + "nameEn": "Requires Configuration", + "slug": "requires-configuration", + "_count": { + "projects": 163 + }, + "projectCount": 163 + }, + { + "id": "cmkjjb37v00064j12b84dsrwg", + "name": "TypeScript", + "nameEn": "TypeScript", + "slug": "typescript", + "_count": { + "projects": 118 + }, + "projectCount": 118 + }, + { + "id": "cmks0yz0h002xl1040w65w47d", + "name": "AI代理", + "nameEn": "AI Agents", + "slug": "ai-agents", + "_count": { + "projects": 52 + }, + "projectCount": 52 + }, + { + "id": "cmkql448t0002l504m7bkovze", + "name": "自动化", + "nameEn": "Automation", + "slug": "automation", + "_count": { + "projects": 46 + }, + "projectCount": 46 + }, + { + "id": "cmkqjvuo5000ejr04y9ksio48", + "name": "Docker", + "nameEn": "Docker", + "slug": "docker", + "_count": { + "projects": 43 + }, + "projectCount": 43 + }, + { + "id": "cmkjjb37v00074j122wpemyas", + "name": "Node.js", + "nameEn": "Node.js", + "slug": "nodejs", + "_count": { + "projects": 40 + }, + "projectCount": 40 + }, + { + "id": "cmkoutfvz0005jr04knetubim", + "name": "JavaScript", + "nameEn": "JavaScript", + "slug": "javascript", + "_count": { + "projects": 34 + }, + "projectCount": 34 + }, + { + "id": "cmkqklwxm0018jr04zyzlrmlv", + "name": "React", + "nameEn": "React", + "slug": "react", + "_count": { + "projects": 34 + }, + "projectCount": 34 + }, + { + "id": "cmkqjgpzq0002l104qknt9pho", + "name": "开源", + "nameEn": "Open Source", + "slug": "open-source", + "_count": { + "projects": 33 + }, + "projectCount": 33 + }, + { + "id": "cmkqnvcbg0001jo04us31pcaj", + "name": "低学习成本", + "nameEn": "Low Learning Curve", + "slug": "low-learning-curve", + "_count": { + "projects": 31 + }, + "projectCount": 31 + }, + { + "id": "cmkqk1dbi000ljr045f2rm18m", + "name": "PyTorch", + "nameEn": "PyTorch", + "slug": "pytorch", + "_count": { + "projects": 30 + }, + "projectCount": 30 + }, + { + "id": "cmkrv2jpg0000l204swrx5xh4", + "name": "LangChain", + "nameEn": "LangChain", + "slug": "langchain", + "_count": { + "projects": 29 + }, + "projectCount": 29 + }, + { + "id": "cmkqlcukz000dl5044c6z8542", + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "slug": "multi-agent-system", + "_count": { + "projects": 28 + }, + "projectCount": 28 + }, + { + "id": "cmkqk1dc5000ojr04jq0exq1z", + "name": "大语言模型", + "nameEn": null, + "slug": "大语言模型", + "_count": { + "projects": 25 + }, + "projectCount": 25 + }, + { + "id": "cmkqimwxl0000jx04l8q0rdzo", + "name": "LLM", + "nameEn": "LLM", + "slug": "llm", + "_count": { + "projects": 22 + }, + "projectCount": 22 + }, + { + "id": "cmks0rbk1002jl104uc7yg2xv", + "name": "Go", + "nameEn": "Go", + "slug": "go", + "_count": { + "projects": 20 + }, + "projectCount": 20 + }, + { + "id": "cmkqm1c6j0003jl04clkn9qyb", + "name": "企业级", + "nameEn": "Enterprise", + "slug": "enterprise", + "_count": { + "projects": 20 + }, + "projectCount": 20 + }, + { + "id": "cmkqnn8hj0006l504j2uedblz", + "name": "需要基础", + "nameEn": "Requires Basics", + "slug": "requires-basics", + "_count": { + "projects": 20 + }, + "projectCount": 20 + }, + { + "id": "cmks0yz1e002yl104nw4apfcq", + "name": "Library", + "nameEn": "Library", + "slug": "library", + "_count": { + "projects": 18 + }, + "projectCount": 18 + }, + { + "id": "cmkrx8euz0007ky04hrgq5ryg", + "name": "MCP", + "nameEn": "Model Context Protocol", + "slug": "model-context-protocol", + "_count": { + "projects": 18 + }, + "projectCount": 18 + }, + { + "id": "cmks16lb0003ml104acf4zi7e", + "name": "Markdown", + "nameEn": "Markdown", + "slug": "markdown", + "_count": { + "projects": 17 + }, + "projectCount": 17 + }, + { + "id": "cmkqklwr20016jr04opezrtpo", + "name": "Next.js", + "nameEn": "Next.js", + "slug": "nextjs", + "_count": { + "projects": 17 + }, + "projectCount": 17 + }, + { + "id": "cmks003y10015l104xruieqo9", + "name": "RAG", + "nameEn": "RAG", + "slug": "rag", + "_count": { + "projects": 17 + }, + "projectCount": 17 + }, + { + "id": "cmkqm1bzv0000jl04c3ks3w7w", + "name": "Java", + "nameEn": "Java", + "slug": "java", + "_count": { + "projects": 16 + }, + "projectCount": 16 + }, + { + "id": "cmks0c9ll0022l10436svssah", + "name": "MIT许可", + "nameEn": "MIT License", + "slug": "mit-license", + "_count": { + "projects": 16 + }, + "projectCount": 16 + }, + { + "id": "cmkqnn8gl0005l5042jdeuuur", + "name": "LangGraph", + "nameEn": "LangGraph", + "slug": "langgraph", + "_count": { + "projects": 15 + }, + "projectCount": 15 + }, + { + "id": "cmkrx664z0000ky0481j124cq", + "name": "FastAPI", + "nameEn": "FastAPI", + "slug": "fastapi", + "_count": { + "projects": 14 + }, + "projectCount": 14 + }, + { + "id": "cmkqjvuir0008jr048591dzwp", + "name": "Rust", + "nameEn": "Rust", + "slug": "rust", + "_count": { + "projects": 14 + }, + "projectCount": 14 + }, + { + "id": "cmkrzlq020001l104sosii49r", + "name": "复杂部署", + "nameEn": "Complex Deployment", + "slug": "complex-deployment", + "_count": { + "projects": 14 + }, + "projectCount": 14 + }, + { + "id": "cmkjjb38l000c4j12oucpveph", + "name": "工作流自动化", + "nameEn": "Workflow Automation", + "slug": "workflow-automation", + "_count": { + "projects": 14 + }, + "projectCount": 14 + }, + { + "id": "cmks3iu8m006wl104ndk8no10", + "name": "C#", + "nameEn": "C#", + "slug": "c", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmkqnn8mm0007l5045q6z4zb0", + "name": "OpenAI", + "nameEn": "OpenAI", + "slug": "openai", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmkrzvdfk000tl104jsq77zig", + "name": "OpenAI API", + "nameEn": "OpenAI API", + "slug": "openai-api", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmks3d1wy006ll104gltxc3et", + "name": "SDK", + "nameEn": "SDK", + "slug": "sdk", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmks1aoxo003xl104gap1drce", + "name": "强化学习", + "nameEn": "Reinforcement Learning", + "slug": "reinforcement-learning", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmks1aoyn003yl104r4zspprz", + "name": "机器学习", + "nameEn": "Machine Learning", + "slug": "machine-learning", + "_count": { + "projects": 11 + }, + "projectCount": 11 + }, + { + "id": "cmksczul60015jv04ft4n1cb2", + "name": "GitHub", + "nameEn": "GitHub", + "slug": "github", + "_count": { + "projects": 10 + }, + "projectCount": 10 + }, + { + "id": "cmks0m380002gl104o6f9cjtj", + "name": "PostgreSQL", + "nameEn": "PostgreSQL", + "slug": "postgresql", + "_count": { + "projects": 10 + }, + "projectCount": 10 + }, + { + "id": "cmkrx8f0j000aky046uomv3rs", + "name": "多模态", + "nameEn": "Multimodal", + "slug": "multimodal", + "_count": { + "projects": 10 + }, + "projectCount": 10 + }, + { + "id": "cmkqjs7e50004jr042mrpi3ac", + "name": "桌面应用", + "nameEn": null, + "slug": "桌面应用", + "_count": { + "projects": 10 + }, + "projectCount": 10 + }, + { + "id": "cmkqk4i0d000vjr04ai18b8h3", + "name": "知识管理", + "nameEn": null, + "slug": "知识管理", + "_count": { + "projects": 10 + }, + "projectCount": 10 + }, + { + "id": "cmkqk4i0g000wjr04t82lzvaq", + "name": "向量数据库", + "nameEn": null, + "slug": "向量数据库", + "_count": { + "projects": 9 + }, + "projectCount": 9 + }, + { + "id": "cmkrzlq0q0003l10453qhsniu", + "name": "Transformers", + "nameEn": "Transformers", + "slug": "transformers", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmks1ubzb004pl104mvs08pmu", + "name": "vLLM", + "nameEn": "vLLM", + "slug": "vllm", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmks0eqvq0028l10426ogrvkb", + "name": "云端服务", + "nameEn": "Cloud Service", + "slug": "cloud-service", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmks13z53003el104re4468xt", + "name": "代码生成", + "nameEn": "Code Generation", + "slug": "code-generation", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmks05ci1001gl104lus7os2q", + "name": "企业级AI应用", + "nameEn": "Enterprise AI", + "slug": "enterprise-ai", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmks1s7p2004il104kpwprttq", + "name": "智能体框架", + "nameEn": "Agent Framework", + "slug": "agent-framework", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmkqjs7dw0003jr04uy2bguck", + "name": "跨平台", + "nameEn": null, + "slug": "跨平台", + "_count": { + "projects": 8 + }, + "projectCount": 8 + }, + { + "id": "cmkqklwxr0019jr048wp0hds8", + "name": "AI 助手", + "nameEn": "AI Assistant", + "slug": "ai-assistant", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmks5ey0j001el204vjk69nwg", + "name": "AI安全", + "nameEn": "AI Security", + "slug": "ai-security", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmkqjs77s0000jr041cypbjkn", + "name": "Electron", + "nameEn": "Electron", + "slug": "electron", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmkry59tc0001jy04kr21i343", + "name": "Playwright", + "nameEn": "Playwright", + "slug": "playwright", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmk9fpg5f0003kt04fcgbvj7y", + "name": "多智能体", + "nameEn": "Multi-Agent", + "slug": "multi-agent", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmkrzxk4i0011l1045cubzwwr", + "name": "深度学习", + "nameEn": "Deep Learning", + "slug": "deep-learning", + "_count": { + "projects": 7 + }, + "projectCount": 7 + }, + { + "id": "cmks13z46003dl1047ba0entr", + "name": "AI代理框架", + "nameEn": "AI Agent Framework", + "slug": "ai-agent-framework", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkry59u70003jy049eoxzkc7", + "name": "AI研究", + "nameEn": "AI Research", + "slug": "ai-research", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmks2a6r1005il104ormxbqud", + "name": "Web应用", + "nameEn": "Web Application", + "slug": "web-application", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkshrboj0000la04h6bmugvj", + "name": "学术研究", + "nameEn": "Academic Research", + "slug": "academic-research", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmks112wx0039l104zltcl2hp", + "name": "工作流编排", + "nameEn": "Workflow Orchestration", + "slug": "workflow-orchestration", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkrzvdfe000sl104q0gge67f", + "name": "教程", + "nameEn": "Tutorial", + "slug": "tutorial", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmks3w0g0000bl904u4lmk5d5", + "name": "浏览器自动化", + "nameEn": "Browser Automation", + "slug": "browser-automation", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkt8m55q000nla04kgfld9x3", + "name": "知识图谱", + "nameEn": "Knowledge Graph", + "slug": "knowledge-graph", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkqklwxj0017jr04czubkbbi", + "name": "知识库", + "nameEn": "Knowledge Base", + "slug": "knowledge-base", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkshubus0004la04zjuh5nn5", + "name": "自主智能体", + "nameEn": "Autonomous Agents", + "slug": "autonomous-agents", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmkqk4i0d000ujr045d2njmc7", + "name": "隐私保护", + "nameEn": null, + "slug": "隐私保护", + "_count": { + "projects": 6 + }, + "projectCount": 6 + }, + { + "id": "cmks02o6m001al104gi1jztpn", + "name": "Apache-2.0", + "nameEn": "Apache-2.0", + "slug": "apache-20", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmks4roac000el204paypouzl", + "name": "CLI", + "nameEn": "CLI", + "slug": "cli", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkt7yhut0000la040ij92vgk", + "name": "MCP协议", + "nameEn": "MCP Protocol", + "slug": "mcp-protocol", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmks5rr2e0020l204sn9ydvka", + "name": "Nest.js", + "nameEn": "Nest.js", + "slug": "nestjs", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkjjb37z00084j121651lnjl", + "name": "Vue.js", + "nameEn": "Vue.js", + "slug": "vuejs", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmksg1wc90061jv04114izr2d", + "name": "Web自动化", + "nameEn": "Web Automation", + "slug": "web-automation", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkuulu5d000jjc04u7hx67sz", + "name": "分布式系统", + "nameEn": "Distributed Systems", + "slug": "distributed-systems", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkqimx3n0001jx043mvrmarx", + "name": "可视化", + "nameEn": "Visualization", + "slug": "visualization", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmksf0ik1004ijv047hiusscw", + "name": "多模态AI", + "nameEn": "Multimodal AI", + "slug": "multimodal-ai", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmktoexz8001wld046f13barg", + "name": "多语言支持", + "nameEn": "Multi-language Support", + "slug": "multi-language-support", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmks2gqie005ol104v4d6nvck", + "name": "数据分析", + "nameEn": "Data Analytics", + "slug": "data-analytics", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmks0equs0026l104sl4td34d", + "name": "聊天机器人", + "nameEn": "Chatbot", + "slug": "chatbot", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkjjb38j000b4j125a3fg282", + "name": "自托管", + "nameEn": "Self-hosted", + "slug": "self-hosted", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmktkj5to001hl704wtmqjft4", + "name": "自然语言处理", + "nameEn": "Natural Language Processing", + "slug": "natural-language-processing", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkrzxk4a0010l104u7irj9je", + "name": "计算机视觉", + "nameEn": "Computer Vision", + "slug": "computer-vision", + "_count": { + "projects": 5 + }, + "projectCount": 5 + }, + { + "id": "cmkto2g8o0019ld04b61pgj4y", + "name": "AI研究资源", + "nameEn": "AI Research Resource", + "slug": "ai-research-resource", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmktk5hid000sl7049a2bo5al", + "name": "Benchmark", + "nameEn": "Benchmark", + "slug": "benchmark", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkv6j7uq000gk4043x1gfnp1", + "name": "Bun", + "nameEn": "Bun", + "slug": "bun", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkti8i470000kz04bpsajkzk", + "name": "ChromaDB", + "nameEn": "ChromaDB", + "slug": "chromadb", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmks47ct90013l904x03rupwb", + "name": "Flask", + "nameEn": "Flask", + "slug": "flask", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkql9bho0007l50406oflxr0", + "name": "Gradio", + "nameEn": "Gradio", + "slug": "gradio", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmks112qf0034l104gkihwp10", + "name": "JavaScript/TypeScript", + "nameEn": "JavaScript/TypeScript", + "slug": "javascripttypescript", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmksfnrz1005qjv044pnraikr", + "name": "LLM应用", + "nameEn": "LLM Applications", + "slug": "llm-applications", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmks1s7ut004jl104gvlybgfs", + "name": "LiteLLM", + "nameEn": "LiteLLM", + "slug": "litellm", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmks4pb54000bl204erpb9bbp", + "name": "LlamaIndex", + "nameEn": "LlamaIndex", + "slug": "llamaindex", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkqimx480003jx04bcqob7pb", + "name": "NLP", + "nameEn": "NLP", + "slug": "nlp", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkqm1c690001jl04ge5elv46", + "name": "Spring Boot", + "nameEn": "Spring Boot", + "slug": "spring-boot", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmks2a6l3005gl1040u4s0k4s", + "name": "Streamlit", + "nameEn": "Streamlit", + "slug": "streamlit", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkth0k4x0026ju04t0euxxwk", + "name": "VS Code扩展", + "nameEn": "VS Code Extension", + "slug": "vs-code-extension", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkscxy490012jv04rf4k4h4h", + "name": "学术资源", + "nameEn": "Academic Resource", + "slug": "academic-resource", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkscgc0z0007jv04nwmzbn8c", + "name": "工具调用", + "nameEn": "Tool Calling", + "slug": "tool-calling", + "_count": { + "projects": 4 + }, + "projectCount": 4 + }, + { + "id": "cmkuxtw0m002ojm04pl9qazxs", + "name": "用户通知", + "nameEn": "User Notification", + "slug": "user-notification", + "_count": { + "projects": 1 + }, + "projectCount": 1 + } +] diff --git a/.sisyphus/reports/tag-semantic-prune-final-result-2026-02-21.json b/.sisyphus/reports/tag-semantic-prune-final-result-2026-02-21.json new file mode 100644 index 0000000..489a550 --- /dev/null +++ b/.sisyphus/reports/tag-semantic-prune-final-result-2026-02-21.json @@ -0,0 +1,132 @@ +{ + "executedAt": "2026-02-21T04:05:08.555Z", + "totalTags": 83, + "totalProjectTags": 1547, + "zeroTags": 0, + "totalProjects": 454, + "projectsWithTags": 454, + "projectsWithoutTags": 0, + "aiTagExists": false, + "removedNoise": [ + "开源", + "学术资源", + "复杂部署", + "用户通知", + "需要配置", + "低学习成本", + "云端服务", + "MIT许可", + "Apache-2.0", + "教程", + "企业级", + "需要基础", + "多语言支持", + "AI研究资源", + "跨平台", + "自托管", + "学术研究" + ], + "removedNoiseStillExists": [], + "topTags": [ + { + "name": "Python", + "nameEn": "Python", + "projectCount": 268 + }, + { + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projectCount": 215 + }, + { + "name": "TypeScript", + "nameEn": "TypeScript", + "projectCount": 118 + }, + { + "name": "AI代理", + "nameEn": "AI Agents", + "projectCount": 54 + }, + { + "name": "自动化", + "nameEn": "Automation", + "projectCount": 47 + }, + { + "name": "Docker", + "nameEn": "Docker", + "projectCount": 43 + }, + { + "name": "Node.js", + "nameEn": "Node.js", + "projectCount": 40 + }, + { + "name": "JavaScript", + "nameEn": "JavaScript", + "projectCount": 34 + }, + { + "name": "React", + "nameEn": "React", + "projectCount": 34 + }, + { + "name": "PyTorch", + "nameEn": "PyTorch", + "projectCount": 30 + }, + { + "name": "LangChain", + "nameEn": "LangChain", + "projectCount": 29 + }, + { + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projectCount": 28 + }, + { + "name": "大语言模型", + "nameEn": null, + "projectCount": 25 + }, + { + "name": "LLM", + "nameEn": "LLM", + "projectCount": 22 + }, + { + "name": "Go", + "nameEn": "Go", + "projectCount": 20 + }, + { + "name": "Library", + "nameEn": "Library", + "projectCount": 18 + }, + { + "name": "MCP", + "nameEn": "Model Context Protocol", + "projectCount": 18 + }, + { + "name": "RAG", + "nameEn": "RAG", + "projectCount": 17 + }, + { + "name": "Next.js", + "nameEn": "Next.js", + "projectCount": 17 + }, + { + "name": "Markdown", + "nameEn": "Markdown", + "projectCount": 17 + } + ] +} diff --git a/.sisyphus/reports/tag-semantic-prune-safe-result-2026-02-21.json b/.sisyphus/reports/tag-semantic-prune-safe-result-2026-02-21.json new file mode 100644 index 0000000..cb5018a --- /dev/null +++ b/.sisyphus/reports/tag-semantic-prune-safe-result-2026-02-21.json @@ -0,0 +1,127 @@ +{ + "executedAt": "2026-02-21T04:03:10.320Z", + "removedNames": [ + "自托管", + "跨平台", + "企业级", + "需要基础", + "AI研究资源", + "多语言支持", + "教程", + "Apache-2.0", + "学术研究", + "MIT许可", + "云端服务", + "低学习成本" + ], + "removedStillExists": [], + "totalTags": 88, + "totalProjectTags": 1754, + "zeroTags": 0, + "totalProjects": 454, + "projectsWithTags": 454, + "projectsWithoutTags": 0, + "aiTagExists": false, + "topTags": [ + { + "name": "Python", + "nameEn": "Python", + "projectCount": 268 + }, + { + "name": "AI开发工具", + "nameEn": "AI Development Tool", + "projectCount": 213 + }, + { + "name": "需要配置", + "nameEn": "Requires Configuration", + "projectCount": 163 + }, + { + "name": "TypeScript", + "nameEn": "TypeScript", + "projectCount": 118 + }, + { + "name": "AI代理", + "nameEn": "AI Agents", + "projectCount": 52 + }, + { + "name": "自动化", + "nameEn": "Automation", + "projectCount": 46 + }, + { + "name": "Docker", + "nameEn": "Docker", + "projectCount": 43 + }, + { + "name": "Node.js", + "nameEn": "Node.js", + "projectCount": 40 + }, + { + "name": "JavaScript", + "nameEn": "JavaScript", + "projectCount": 34 + }, + { + "name": "React", + "nameEn": "React", + "projectCount": 34 + }, + { + "name": "开源", + "nameEn": "Open Source", + "projectCount": 33 + }, + { + "name": "PyTorch", + "nameEn": "PyTorch", + "projectCount": 30 + }, + { + "name": "LangChain", + "nameEn": "LangChain", + "projectCount": 29 + }, + { + "name": "多智能体系统", + "nameEn": "Multi-Agent System", + "projectCount": 28 + }, + { + "name": "大语言模型", + "nameEn": null, + "projectCount": 25 + }, + { + "name": "LLM", + "nameEn": "LLM", + "projectCount": 22 + }, + { + "name": "Go", + "nameEn": "Go", + "projectCount": 20 + }, + { + "name": "MCP", + "nameEn": "Model Context Protocol", + "projectCount": 18 + }, + { + "name": "Library", + "nameEn": "Library", + "projectCount": 18 + }, + { + "name": "RAG", + "nameEn": "RAG", + "projectCount": 17 + } + ] +} diff --git a/.sisyphus/sql/tag-cap-100-2026-02-21.sql b/.sisyphus/sql/tag-cap-100-2026-02-21.sql new file mode 100644 index 0000000..558c387 --- /dev/null +++ b/.sisyphus/sql/tag-cap-100-2026-02-21.sql @@ -0,0 +1,211 @@ +BEGIN; + +DELETE FROM "project_tags" +WHERE "tagId" NOT IN ( + 'cmk9fpg4h0000kt048l3a2nqu', + 'cmkjjb37v00064j12b84dsrwg', + 'cmkqimx520005jx04vyegybp9', + 'cmks16lb0003ml104acf4zi7e', + 'cmks0yz0h002xl1040w65w47d', + 'cmkqjgpzq0002l104qknt9pho', + 'cmkql448t0002l504m7bkovze', + 'cmkqm1bzv0000jl04c3ks3w7w', + 'cmkoutfvz0005jr04knetubim', + 'cmks0rbk1002jl104uc7yg2xv', + 'cmks3iu8m006wl104ndk8no10', + 'cmkqk1dc5000ojr04jq0exq1z', + 'cmkqimwxl0000jx04l8q0rdzo', + 'cmks0yz1e002yl104nw4apfcq', + 'cmkqjvuo5000ejr04y9ksio48', + 'cmkjjb37v00074j122wpemyas', + 'cmkqnvcbg0001jo04us31pcaj', + 'cmkrzlq020001l104sosii49r', + 'cmks1aoyn003yl104r4zspprz', + 'cmks5ey0j001el204vjk69nwg', + 'cmkshrboj0000la04h6bmugvj', + 'cmkscgc0z0007jv04nwmzbn8c', + 'cmkscxy490012jv04rf4k4h4h', + 'cmkuxtw0m002ojm04pl9qazxs', + 'cmkqklwxm0018jr04zyzlrmlv', + 'cmkqk1dbi000ljr045f2rm18m', + 'cmkrv2jpg0000l204swrx5xh4', + 'cmkqlcukz000dl5044c6z8542', + 'cmkqm1c6j0003jl04clkn9qyb', + 'cmkqnn8hj0006l504j2uedblz', + 'cmkrx8euz0007ky04hrgq5ryg', + 'cmkqklwr20016jr04opezrtpo', + 'cmks003y10015l104xruieqo9', + 'cmks0c9ll0022l10436svssah', + 'cmkqnn8gl0005l5042jdeuuur', + 'cmkrx664z0000ky0481j124cq', + 'cmkqjvuir0008jr048591dzwp', + 'cmkjjb38l000c4j12oucpveph', + 'cmkqnn8mm0007l5045q6z4zb0', + 'cmkrzvdfk000tl104jsq77zig', + 'cmks3d1wy006ll104gltxc3et', + 'cmks1aoxo003xl104gap1drce', + 'cmksczul60015jv04ft4n1cb2', + 'cmks0m380002gl104o6f9cjtj', + 'cmkrx8f0j000aky046uomv3rs', + 'cmkqjs7e50004jr042mrpi3ac', + 'cmkqk4i0d000vjr04ai18b8h3', + 'cmkqk4i0g000wjr04t82lzvaq', + 'cmkrzlq0q0003l10453qhsniu', + 'cmks1ubzb004pl104mvs08pmu', + 'cmks0eqvq0028l10426ogrvkb', + 'cmks13z53003el104re4468xt', + 'cmks05ci1001gl104lus7os2q', + 'cmks1s7p2004il104kpwprttq', + 'cmkqjs7dw0003jr04uy2bguck', + 'cmkqklwxr0019jr048wp0hds8', + 'cmkqjs77s0000jr041cypbjkn', + 'cmkry59tc0001jy04kr21i343', + 'cmk9fpg5f0003kt04fcgbvj7y', + 'cmkrzxk4i0011l1045cubzwwr', + 'cmks13z46003dl1047ba0entr', + 'cmkry59u70003jy049eoxzkc7', + 'cmks2a6r1005il104ormxbqud', + 'cmks112wx0039l104zltcl2hp', + 'cmkrzvdfe000sl104q0gge67f', + 'cmks3w0g0000bl904u4lmk5d5', + 'cmkt8m55q000nla04kgfld9x3', + 'cmkqklwxj0017jr04czubkbbi', + 'cmkshubus0004la04zjuh5nn5', + 'cmkqk4i0d000ujr045d2njmc7', + 'cmks02o6m001al104gi1jztpn', + 'cmks4roac000el204paypouzl', + 'cmkt7yhut0000la040ij92vgk', + 'cmks5rr2e0020l204sn9ydvka', + 'cmkjjb37z00084j121651lnjl', + 'cmksg1wc90061jv04114izr2d', + 'cmkuulu5d000jjc04u7hx67sz', + 'cmkqimx3n0001jx043mvrmarx', + 'cmksf0ik1004ijv047hiusscw', + 'cmktoexz8001wld046f13barg', + 'cmks2gqie005ol104v4d6nvck', + 'cmks0equs0026l104sl4td34d', + 'cmkjjb38j000b4j125a3fg282', + 'cmktkj5to001hl704wtmqjft4', + 'cmkrzxk4a0010l104u7irj9je', + 'cmkto2g8o0019ld04b61pgj4y', + 'cmktk5hid000sl7049a2bo5al', + 'cmkv6j7uq000gk4043x1gfnp1', + 'cmkti8i470000kz04bpsajkzk', + 'cmks47ct90013l904x03rupwb', + 'cmkql9bho0007l50406oflxr0', + 'cmks112qf0034l104gkihwp10', + 'cmks1s7ut004jl104gvlybgfs', + 'cmks4pb54000bl204erpb9bbp', + 'cmksfnrz1005qjv044pnraikr', + 'cmkqimx480003jx04bcqob7pb', + 'cmkqm1c690001jl04ge5elv46', + 'cmks2a6l3005gl1040u4s0k4s', + 'cmkth0k4x0026ju04t0euxxwk', + 'cmkqnj1pt0001l504vmrywqeg' +); + +DELETE FROM "tags" +WHERE "id" NOT IN ( + 'cmk9fpg4h0000kt048l3a2nqu', + 'cmkjjb37v00064j12b84dsrwg', + 'cmkqimx520005jx04vyegybp9', + 'cmks16lb0003ml104acf4zi7e', + 'cmks0yz0h002xl1040w65w47d', + 'cmkqjgpzq0002l104qknt9pho', + 'cmkql448t0002l504m7bkovze', + 'cmkqm1bzv0000jl04c3ks3w7w', + 'cmkoutfvz0005jr04knetubim', + 'cmks0rbk1002jl104uc7yg2xv', + 'cmks3iu8m006wl104ndk8no10', + 'cmkqk1dc5000ojr04jq0exq1z', + 'cmkqimwxl0000jx04l8q0rdzo', + 'cmks0yz1e002yl104nw4apfcq', + 'cmkqjvuo5000ejr04y9ksio48', + 'cmkjjb37v00074j122wpemyas', + 'cmkqnvcbg0001jo04us31pcaj', + 'cmkrzlq020001l104sosii49r', + 'cmks1aoyn003yl104r4zspprz', + 'cmks5ey0j001el204vjk69nwg', + 'cmkshrboj0000la04h6bmugvj', + 'cmkscgc0z0007jv04nwmzbn8c', + 'cmkscxy490012jv04rf4k4h4h', + 'cmkuxtw0m002ojm04pl9qazxs', + 'cmkqklwxm0018jr04zyzlrmlv', + 'cmkqk1dbi000ljr045f2rm18m', + 'cmkrv2jpg0000l204swrx5xh4', + 'cmkqlcukz000dl5044c6z8542', + 'cmkqm1c6j0003jl04clkn9qyb', + 'cmkqnn8hj0006l504j2uedblz', + 'cmkrx8euz0007ky04hrgq5ryg', + 'cmkqklwr20016jr04opezrtpo', + 'cmks003y10015l104xruieqo9', + 'cmks0c9ll0022l10436svssah', + 'cmkqnn8gl0005l5042jdeuuur', + 'cmkrx664z0000ky0481j124cq', + 'cmkqjvuir0008jr048591dzwp', + 'cmkjjb38l000c4j12oucpveph', + 'cmkqnn8mm0007l5045q6z4zb0', + 'cmkrzvdfk000tl104jsq77zig', + 'cmks3d1wy006ll104gltxc3et', + 'cmks1aoxo003xl104gap1drce', + 'cmksczul60015jv04ft4n1cb2', + 'cmks0m380002gl104o6f9cjtj', + 'cmkrx8f0j000aky046uomv3rs', + 'cmkqjs7e50004jr042mrpi3ac', + 'cmkqk4i0d000vjr04ai18b8h3', + 'cmkqk4i0g000wjr04t82lzvaq', + 'cmkrzlq0q0003l10453qhsniu', + 'cmks1ubzb004pl104mvs08pmu', + 'cmks0eqvq0028l10426ogrvkb', + 'cmks13z53003el104re4468xt', + 'cmks05ci1001gl104lus7os2q', + 'cmks1s7p2004il104kpwprttq', + 'cmkqjs7dw0003jr04uy2bguck', + 'cmkqklwxr0019jr048wp0hds8', + 'cmkqjs77s0000jr041cypbjkn', + 'cmkry59tc0001jy04kr21i343', + 'cmk9fpg5f0003kt04fcgbvj7y', + 'cmkrzxk4i0011l1045cubzwwr', + 'cmks13z46003dl1047ba0entr', + 'cmkry59u70003jy049eoxzkc7', + 'cmks2a6r1005il104ormxbqud', + 'cmks112wx0039l104zltcl2hp', + 'cmkrzvdfe000sl104q0gge67f', + 'cmks3w0g0000bl904u4lmk5d5', + 'cmkt8m55q000nla04kgfld9x3', + 'cmkqklwxj0017jr04czubkbbi', + 'cmkshubus0004la04zjuh5nn5', + 'cmkqk4i0d000ujr045d2njmc7', + 'cmks02o6m001al104gi1jztpn', + 'cmks4roac000el204paypouzl', + 'cmkt7yhut0000la040ij92vgk', + 'cmks5rr2e0020l204sn9ydvka', + 'cmkjjb37z00084j121651lnjl', + 'cmksg1wc90061jv04114izr2d', + 'cmkuulu5d000jjc04u7hx67sz', + 'cmkqimx3n0001jx043mvrmarx', + 'cmksf0ik1004ijv047hiusscw', + 'cmktoexz8001wld046f13barg', + 'cmks2gqie005ol104v4d6nvck', + 'cmks0equs0026l104sl4td34d', + 'cmkjjb38j000b4j125a3fg282', + 'cmktkj5to001hl704wtmqjft4', + 'cmkrzxk4a0010l104u7irj9je', + 'cmkto2g8o0019ld04b61pgj4y', + 'cmktk5hid000sl7049a2bo5al', + 'cmkv6j7uq000gk4043x1gfnp1', + 'cmkti8i470000kz04bpsajkzk', + 'cmks47ct90013l904x03rupwb', + 'cmkql9bho0007l50406oflxr0', + 'cmks112qf0034l104gkihwp10', + 'cmks1s7ut004jl104gvlybgfs', + 'cmks4pb54000bl204erpb9bbp', + 'cmksfnrz1005qjv044pnraikr', + 'cmkqimx480003jx04bcqob7pb', + 'cmkqm1c690001jl04ge5elv46', + 'cmks2a6l3005gl1040u4s0k4s', + 'cmkth0k4x0026ju04t0euxxwk', + 'cmkqnj1pt0001l504vmrywqeg' +); + +COMMIT; diff --git a/.sisyphus/sql/tag-cleanup-2026-02-21.sql b/.sisyphus/sql/tag-cleanup-2026-02-21.sql new file mode 100644 index 0000000..1eca766 --- /dev/null +++ b/.sisyphus/sql/tag-cleanup-2026-02-21.sql @@ -0,0 +1,46 @@ +BEGIN; + +-- Step 1: Merge duplicate tags by high-confidence canonicalized nameEn groups +WITH merge_map(source_id, target_id) AS ( +VALUES + ('cmkoutg0o0006jr04goozjhft', 'cmkqimx520005jx04vyegybp9'), + ('cmkjjb387000a4j12pdf123zn', 'cmks0yz0h002xl1040w65w47d'), + ('cmkun0ao70048jx04atm2lwwq', 'cmkryxmob0003l80414uo5zqz'), + ('cmkrzqdlu000fl104qmy9gu2u', 'cmkqlcukz000dl5044c6z8542'), + ('cmktk3biu000nl704iiohmv4i', 'cmksdlj9o0029jv04x9tdyc11'), + ('cmktpotkp003eld04mv09ckde', 'cmkshubus0004la04zjuh5nn5') +) +INSERT INTO "project_tags" ("projectId", "tagId") +SELECT pt."projectId", mm.target_id +FROM "project_tags" pt +JOIN merge_map mm ON mm.source_id = pt."tagId" +ON CONFLICT ("projectId", "tagId") DO NOTHING; + +WITH merge_map(source_id, target_id) AS ( +VALUES + ('cmkoutg0o0006jr04goozjhft', 'cmkqimx520005jx04vyegybp9'), + ('cmkjjb387000a4j12pdf123zn', 'cmks0yz0h002xl1040w65w47d'), + ('cmkun0ao70048jx04atm2lwwq', 'cmkryxmob0003l80414uo5zqz'), + ('cmkrzqdlu000fl104qmy9gu2u', 'cmkqlcukz000dl5044c6z8542'), + ('cmktk3biu000nl704iiohmv4i', 'cmksdlj9o0029jv04x9tdyc11'), + ('cmktpotkp003eld04mv09ckde', 'cmkshubus0004la04zjuh5nn5') +) +DELETE FROM "tags" t +USING merge_map mm +WHERE t."id" = mm.source_id; + +-- Step 2: Fill missing English names for ASCII-only tags +UPDATE "tags" +SET "nameEn" = "name" +WHERE ("nameEn" IS NULL OR "nameEn" = '') + AND "name" ~ '^[[:ascii:]]+$'; + +-- Step 3: Delete tags no longer referenced by any project +DELETE FROM "tags" t +WHERE NOT EXISTS ( + SELECT 1 + FROM "project_tags" pt + WHERE pt."tagId" = t."id" +); + +COMMIT; diff --git a/.sisyphus/sql/tag-semantic-prune-final-2026-02-21.sql b/.sisyphus/sql/tag-semantic-prune-final-2026-02-21.sql new file mode 100644 index 0000000..ab11465 --- /dev/null +++ b/.sisyphus/sql/tag-semantic-prune-final-2026-02-21.sql @@ -0,0 +1,76 @@ +BEGIN; + +WITH noise AS ( + SELECT id + FROM tags + WHERE name IN ( + '开源', + '学术资源', + '复杂部署', + '用户通知', + '需要配置' + ) +), +projects_without_meaningful_tags AS ( + SELECT p.id, p.name + FROM projects p + LEFT JOIN project_tags pt ON pt."projectId" = p.id + LEFT JOIN noise n ON n.id = pt."tagId" + GROUP BY p.id, p.name + HAVING COUNT(pt."tagId") > 0 AND COUNT(pt."tagId") = COUNT(n.id) +), +fallback_tags AS ( + SELECT + (SELECT id FROM tags WHERE name = 'AI研究' LIMIT 1) AS research_id, + (SELECT id FROM tags WHERE name = 'AI 助手' LIMIT 1) AS assistant_id, + (SELECT id FROM tags WHERE name = 'AI代理' LIMIT 1) AS agent_id, + (SELECT id FROM tags WHERE name = '自动化' LIMIT 1) AS automation_id, + (SELECT id FROM tags WHERE name = 'AI开发工具' LIMIT 1) AS tool_id +), +assignments AS ( + SELECT + p.id AS project_id, + CASE + WHEN p.name ~* '(论文|研究|paper|survey)' THEN (SELECT research_id FROM fallback_tags) + WHEN p.name ~* '(助手|assistant)' THEN (SELECT assistant_id FROM fallback_tags) + WHEN p.name ~* '(框架|agent|代理|智能体)' THEN (SELECT agent_id FROM fallback_tags) + WHEN p.name ~* '(通知|alert|quota|配额)' THEN (SELECT automation_id FROM fallback_tags) + ELSE (SELECT tool_id FROM fallback_tags) + END AS tag_id + FROM projects_without_meaningful_tags p +) +INSERT INTO project_tags ("projectId", "tagId") +SELECT project_id, tag_id +FROM assignments +WHERE tag_id IS NOT NULL +ON CONFLICT ("projectId", "tagId") DO NOTHING; + +WITH noise AS ( + SELECT id + FROM tags + WHERE name IN ( + '开源', + '学术资源', + '复杂部署', + '用户通知', + '需要配置' + ) +) +DELETE FROM project_tags +WHERE "tagId" IN (SELECT id FROM noise); + +WITH noise AS ( + SELECT id + FROM tags + WHERE name IN ( + '开源', + '学术资源', + '复杂部署', + '用户通知', + '需要配置' + ) +) +DELETE FROM tags +WHERE id IN (SELECT id FROM noise); + +COMMIT; diff --git a/.sisyphus/sql/tag-semantic-prune-safe-2026-02-21.sql b/.sisyphus/sql/tag-semantic-prune-safe-2026-02-21.sql new file mode 100644 index 0000000..5e94841 --- /dev/null +++ b/.sisyphus/sql/tag-semantic-prune-safe-2026-02-21.sql @@ -0,0 +1,43 @@ +BEGIN; + +WITH target_tags AS ( + SELECT id FROM tags + WHERE name IN ( + '自托管', + '跨平台', + '企业级', + '需要基础', + 'AI研究资源', + '多语言支持', + '教程', + 'Apache-2.0', + '学术研究', + 'MIT许可', + '云端服务', + '低学习成本' + ) +) +DELETE FROM project_tags +WHERE "tagId" IN (SELECT id FROM target_tags); + +WITH target_tags AS ( + SELECT id FROM tags + WHERE name IN ( + '自托管', + '跨平台', + '企业级', + '需要基础', + 'AI研究资源', + '多语言支持', + '教程', + 'Apache-2.0', + '学术研究', + 'MIT许可', + '云端服务', + '低学习成本' + ) +) +DELETE FROM tags +WHERE id IN (SELECT id FROM target_tags); + +COMMIT; diff --git a/n8n-workflows/README.md b/n8n-workflows/README.md index 4c9d488..7aceb97 100644 --- a/n8n-workflows/README.md +++ b/n8n-workflows/README.md @@ -69,48 +69,49 @@ ### 功能 -每日自动拉取标签,利用 LLM 生成 `merges + updates` 计划,并调用维护 API 执行标签合并。 +每日自动拉取标签,按分桶分块交给 AI Agent 处理,并通过结构化输出解析器强制 JSON 格式,最终调用维护 API 执行合并与 `nameEn` 补全。 ### 执行流程 1. **Schedule Trigger**: 每日 UTC 03:00 触发 2. **Fetch Tags**: 调用 `GET /api/tags` 获取标签和项目计数 -3. **Preprocess Tags**: 预处理排序(按 projectCount) -4. **AI Analyze Tags**: 生成严格 JSON 计划(`merges`、`updates`) -5. **Validate JSON**: 校验输出结构和自合并风险 -6. **Execute Maintenance**: 调用 `POST /api/tags/maintenance` 执行 -7. **Summarize Results**: 输出日报(merged/deleted/updated) +3. **Prepare Chunk Batches**: 预处理并按 bucket + chunk 拆分(默认每块 80) +4. **Tag Merge Agent + Structured Output Parser**: Agent 生成计划,Parser 强制输出 schema +5. **Validate Plan**: 校验覆盖率(`reviewedTagIds` 必须覆盖整块)、ID 合法性、自合并 +6. **Retry Loop**: 校验失败会自动重试(默认 2 次,可配置) +7. **Execute Maintenance**: 仅对校验通过的块调用 `POST /api/tags/maintenance` +8. **Summarize Results**: 汇总 executed/noop/failed_validation/failed_execute ### API 端点 - `GET {API_URL}/api/tags` - 拉取标签列表(含 `_count.projects`) - `POST {API_URL}/api/tags/maintenance` - 执行批量 updates/merges -### 调试 +### 环境变量 -检查每个节点的输出,确保数据格式正确: +在 n8n 进程环境中配置: -- **Calculate Quarter**: 应输出 `quarter`, `startDate`, `endDate` -- **Extract Keywords**: 应输出 `word`, `trendScore`, `quarter` -- **Match Visual Rules**: 应添加 `visualConfig` 字段 -- **Send to API**: 应返回 `success: true` +| 变量名 | 说明 | 默认值 | +| --- | --- | --- | +| `SITE_BASE_URL` | 站点地址 | 无 | +| `WEBHOOK_API_KEY` | 维护 API 鉴权密钥 | 无 | +| `TAG_JANITOR_CHUNK_SIZE` | 每块标签数量 | `80` | +| `TAG_JANITOR_MAX_RETRIES` | 校验失败自动重试次数 | `2` | ### 注意事项 -1. **Google Trends API 限制**: - - Google Trends 有请求频率限制 - - 建议在非高峰期执行工作流 +1. **不要全量一次喂模型**: + - 900+ 标签必须分块,否则大概率返回不完整。 -2. **数据质量**: - - 当前工作流中的 `description` 和 `detailPoints` 是占位符 - - 需要添加 AI 节点(如 OpenAI)来生成真实内容 +2. **结构化输出是硬约束**: + - 由 `Structured Output Parser` 保证格式。 + - `Validate Plan` 仍会做二次校验,防止“格式正确但内容不完整”。 -3. **时区处理**: - - 确保时区设置正确,以便准确计算季度末日期 +3. **失败块不会误执行**: + - 校验不通过的块不会调用维护 API,会在 summary 中归类为失败并给出原因。 ### 扩展建议 -- **AI 内容生成**:在 "Match Visual Rules" 后添加 OpenAI 节点,生成描述和要点 -- **数据验证**:添加验证节点检查数据完整性 -- **错误处理**:添加错误分支,记录失败的关键词 -- **通知**:工作流完成后发送通知(如 Slack、Email) +- 将 `failed_*` 摘要接入 Slack/Telegram 告警 +- 对 `failed_validation` 块做二次人工审核队列 +- 在预处理阶段先做字符串近似聚类,进一步减少 LLM token 消耗 diff --git a/n8n-workflows/tag-janitor-workflow.json b/n8n-workflows/tag-janitor-workflow.json index b58e088..863f7a6 100644 --- a/n8n-workflows/tag-janitor-workflow.json +++ b/n8n-workflows/tag-janitor-workflow.json @@ -30,65 +30,112 @@ }, { "parameters": { - "jsCode": "const response = $input.first().json;\nif (!response.success) {\n throw new Error('Failed to fetch tags: ' + JSON.stringify(response));\n}\n\nconst tags = response.tags;\nconst formatted = tags.map(t => ({\n id: t.id,\n name: t.name,\n nameEn: t.nameEn || '',\n projectCount: t._count?.projects || 0\n}));\n\n// Sort by project count descending\nformatted.sort((a, b) => b.projectCount - a.projectCount);\n\nreturn [{ json: { tags: formatted, total: formatted.length } }];" + "jsCode": "const response = $input.first().json;\nif (!response.success) {\n throw new Error('Failed to fetch tags: ' + JSON.stringify(response));\n}\n\nconst rawTags = Array.isArray(response.tags) ? response.tags : [];\nconst chunkSize = Math.max(20, Math.min(120, Number.parseInt($env.TAG_JANITOR_CHUNK_SIZE || '80', 10) || 80));\n\nconst normalizedTags = rawTags\n .map((tag) => ({\n id: tag.id,\n name: String(tag.name || '').trim(),\n nameEn: String(tag.nameEn || '').trim(),\n projectCount: Number(tag?._count?.projects || 0),\n }))\n .filter((tag) => tag.id && tag.name);\n\nnormalizedTags.sort((a, b) => b.projectCount - a.projectCount || a.name.localeCompare(b.name));\n\nif (normalizedTags.length === 0) {\n return [{\n json: {\n chunkId: 'empty-0',\n bucketKey: 'empty',\n tags: [],\n totalInChunk: 0,\n totalTags: 0,\n retryCount: 0,\n retryFeedback: '',\n status: 'noop',\n shouldExecute: false\n }\n }];\n}\n\nconst bucketMap = new Map();\nfor (const tag of normalizedTags) {\n const seed = (tag.nameEn || tag.name).toLowerCase().trim();\n const normalized = seed.replace(/[^a-z0-9\\u4e00-\\u9fa5]+/g, '');\n\n let bucketKey = 'misc';\n if (normalized.length > 0) {\n const first = normalized[0];\n if (/[a-z0-9]/.test(first)) {\n bucketKey = 'en-' + first;\n } else if (/[\\u4e00-\\u9fa5]/.test(first)) {\n bucketKey = 'zh-' + first;\n }\n }\n\n const list = bucketMap.get(bucketKey) || [];\n list.push(tag);\n bucketMap.set(bucketKey, list);\n}\n\nconst chunks = [];\nfor (const [bucketKey, tags] of bucketMap.entries()) {\n tags.sort((a, b) => b.projectCount - a.projectCount || a.name.localeCompare(b.name));\n for (let i = 0; i < tags.length; i += chunkSize) {\n chunks.push({\n bucketKey,\n tags: tags.slice(i, i + chunkSize)\n });\n }\n}\n\nchunks.sort((a, b) => b.tags.length - a.tags.length);\n\nreturn chunks.map((chunk, idx) => ({\n json: {\n chunkId: chunk.bucketKey + '-' + (idx + 1),\n bucketKey: chunk.bucketKey,\n tags: chunk.tags,\n totalInChunk: chunk.tags.length,\n totalTags: normalizedTags.length,\n retryCount: 0,\n retryFeedback: ''\n }\n}));" }, - "id": "preprocess", - "name": "Preprocess Tags", + "id": "prepare-chunks", + "name": "Prepare Chunk Batches", "type": "n8n-nodes-base.code", "typeVersion": 2, - "position": [440, 0] + "position": [460, 0] }, { "parameters": { - "model": "gpt-4o", - "messages": { - "values": [ - { - "role": "system", - "content": "You are a tag management expert. Analyze tags and identify semantic duplicates for merging and missing English names for completion. Output STRICT JSON only." - }, - { - "role": "user", - "content": "Analyze these tags and identify:\n1. Semantic duplicates to merge (e.g., \"机器学习\" and \"ML\" → keep higher projectCount)\n2. Tags missing nameEn that need English names\n\nTags ({{$json.total}} total):\n{{JSON.stringify($json.tags)}}\n\nOutput STRICT JSON (no markdown):\n{\n \"merges\": [\n {\n \"target\": { \"name\": \"保留的标签\", \"nameEn\": \"Canonical Name\" },\n \"sourceTagIds\": [\"id1\", \"id2\"]\n }\n ],\n \"updates\": [\n { \"tagId\": \"id\", \"nameEn\": \"English Name\" }\n ]\n}\n\nRules:\n- Keep tag with higher projectCount as merge target\n- target can use { \"id\": \"existing\" } to keep existing tag\n- Only include tags needing action (empty arrays if none)\n- nameEn must be proper English, not pinyin" - } - ] + "text": "=Chunk {{$json.chunkId}} from {{$json.bucketKey}}.\\nThis chunk contains {{$json.totalInChunk}} tags out of {{$json.totalTags}} total tags.\\nRetry count: {{$json.retryCount || 0}}.\\nRetry feedback: {{$json.retryFeedback || 'none'}}.\\n\\nOutput MUST be JSON and MUST follow the connected structured parser schema.\\nOnly use tag IDs from this chunk.\\n\\nChunk tags JSON:\\n{{JSON.stringify($json.tags)}}", + "options": { + "systemMessage": "You are a strict tag-governance agent.\\n\\nFor the current chunk only:\\n1) Find semantic duplicates and output merges\\n2) Fill missing or low-quality English names and output updates\\n3) Return reviewedTagIds that fully cover every tag ID in this chunk\\n4) Put uncertain tags into unresolvedTagIds\\n\\nHard rules:\\n- Never reference tag IDs outside the current chunk\\n- Prefer existing target ID with higher projectCount\\n- Do not self-merge\\n- Return no markdown, no prose, JSON only" + }, + "promptType": "define", + "hasOutputParser": true + }, + "id": "tag-merge-agent", + "name": "Tag Merge Agent", + "type": "@n8n/n8n-nodes-langchain.agent", + "typeVersion": 1.8, + "position": [700, 0] + }, + { + "parameters": { + "model": { + "__rl": true, + "mode": "list", + "value": "gpt-4.1-mini", + "cachedResultName": "gpt-4.1-mini" }, "options": { "temperature": 0.1 } }, - "id": "ai-analyze", - "name": "AI Analyze Tags", - "type": "@n8n/n8n-nodes-langchain.openAi", - "typeVersion": 1.8, - "position": [660, 0] + "id": "openai-model", + "name": "OpenAI Chat Model", + "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", + "typeVersion": 1.2, + "position": [700, 220] }, { "parameters": { - "jsCode": "const response = $input.first().json;\nlet plan;\n\ntry {\n const content = response.message?.content || response.text || response;\n plan = typeof content === 'string' ? JSON.parse(content) : content;\n} catch (e) {\n throw new Error('Failed to parse AI response: ' + e.message);\n}\n\nif (!Array.isArray(plan.merges)) plan.merges = [];\nif (!Array.isArray(plan.updates)) plan.updates = [];\n\nfor (const merge of plan.merges) {\n if (merge.target.id && merge.sourceTagIds.includes(merge.target.id)) {\n throw new Error('Self-merge detected: ' + merge.target.id);\n }\n}\n\nif (plan.merges.length === 0 && plan.updates.length === 0) {\n return [{ json: { skipped: true, reason: 'No changes needed' } }];\n}\n\nreturn [{ json: plan }];" + "schemaType": "manual", + "inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"reviewedTagIds\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"unresolvedTagIds\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"merges\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"target\": {\n \"oneOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"id\": { \"type\": \"string\" }\n },\n \"required\": [\"id\"]\n },\n {\n \"type\": \"object\",\n \"properties\": {\n \"name\": { \"type\": \"string\" },\n \"nameEn\": { \"type\": \"string\" }\n },\n \"required\": [\"name\", \"nameEn\"]\n }\n ]\n },\n \"sourceTagIds\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n },\n \"required\": [\"target\", \"sourceTagIds\"]\n }\n },\n \"updates\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"tagId\": { \"type\": \"string\" },\n \"nameEn\": { \"type\": \"string\" }\n },\n \"required\": [\"tagId\", \"nameEn\"]\n }\n }\n },\n \"required\": [\"reviewedTagIds\", \"unresolvedTagIds\", \"merges\", \"updates\"]\n}", + "autoFix": true }, - "id": "validate-json", - "name": "Validate JSON", + "id": "structured-parser", + "name": "Structured Output Parser", + "type": "@n8n/n8n-nodes-langchain.outputParserStructured", + "typeVersion": 1.2, + "position": [960, 220] + }, + { + "parameters": { + "jsCode": "const maxRetries = Math.max(0, Number.parseInt($env.TAG_JANITOR_MAX_RETRIES || '2', 10) || 2);\n\nfunction normalizeIds(input) {\n if (!Array.isArray(input)) return [];\n return [...new Set(input.map((id) => String(id || '').trim()).filter(Boolean))];\n}\n\nfunction safeArray(input) {\n return Array.isArray(input) ? input : [];\n}\n\nreturn $input.all().map((item) => {\n const row = item.json || {};\n const parsed = row.output && typeof row.output === 'object' ? row.output : {};\n\n const tags = safeArray(row.tags);\n const chunkTagIds = normalizeIds(tags.map((tag) => tag.id));\n const chunkTagIdSet = new Set(chunkTagIds);\n\n const reviewedTagIds = normalizeIds(parsed.reviewedTagIds);\n const unresolvedTagIds = normalizeIds(parsed.unresolvedTagIds);\n\n const updates = safeArray(parsed.updates).flatMap((update) => {\n if (!update || typeof update !== 'object') return [];\n const tagId = String(update.tagId || '').trim();\n const nameEn = String(update.nameEn || '').trim();\n if (!tagId || !nameEn) return [];\n return [{ tagId, nameEn }];\n });\n\n const merges = safeArray(parsed.merges).flatMap((merge) => {\n if (!merge || typeof merge !== 'object') return [];\n const sourceTagIds = normalizeIds(merge.sourceTagIds);\n if (sourceTagIds.length === 0) return [];\n\n const target = merge.target;\n if (!target || typeof target !== 'object') return [];\n\n if (typeof target.id === 'string' && target.id.trim()) {\n return [{\n target: { id: target.id.trim() },\n sourceTagIds\n }];\n }\n\n const name = String(target.name || '').trim();\n const nameEn = String(target.nameEn || '').trim();\n if (!name || !nameEn) return [];\n\n return [{\n target: { name, nameEn },\n sourceTagIds\n }];\n });\n\n const errors = [];\n\n const reviewedSet = new Set(reviewedTagIds);\n const missingReviewed = chunkTagIds.filter((id) => !reviewedSet.has(id));\n if (missingReviewed.length > 0) {\n errors.push(`Missing reviewedTagIds coverage: ${missingReviewed.join(', ')}`);\n }\n\n for (const update of updates) {\n if (!chunkTagIdSet.has(update.tagId)) {\n errors.push(`Update references unknown tagId in chunk: ${update.tagId}`);\n }\n }\n\n for (const merge of merges) {\n for (const sourceTagId of merge.sourceTagIds) {\n if (!chunkTagIdSet.has(sourceTagId)) {\n errors.push(`Merge sourceTagId not in chunk: ${sourceTagId}`);\n }\n }\n\n if ('id' in merge.target) {\n if (!chunkTagIdSet.has(merge.target.id)) {\n errors.push(`Merge target.id not in chunk: ${merge.target.id}`);\n }\n if (merge.sourceTagIds.includes(merge.target.id)) {\n errors.push(`Self merge detected: ${merge.target.id}`);\n }\n }\n }\n\n const retryCount = Number(row.retryCount || 0);\n const hasValidationErrors = errors.length > 0;\n const needsRetry = hasValidationErrors && retryCount < maxRetries;\n const shouldExecute = !hasValidationErrors && (updates.length > 0 || merges.length > 0);\n\n let status = 'noop';\n if (needsRetry) status = 'retry';\n else if (hasValidationErrors) status = 'failed_validation';\n else if (shouldExecute) status = 'ready';\n\n return {\n json: {\n ...row,\n validated: {\n reviewedTagIds,\n unresolvedTagIds,\n updates,\n merges\n },\n validationErrors: errors,\n needsRetry,\n shouldExecute,\n status\n }\n };\n});" + }, + "id": "validate-plan", + "name": "Validate Plan", "type": "n8n-nodes-base.code", "typeVersion": 2, - "position": [880, 0] + "position": [960, 0] }, { "parameters": { "conditions": { "boolean": [ { - "value1": "={{$json.skipped}}", + "value1": "={{$json.needsRetry}}", "value2": true } ] } }, - "id": "check-skip", - "name": "Check Skip", + "id": "retry-needed", + "name": "Retry Needed?", "type": "n8n-nodes-base.if", "typeVersion": 2, - "position": [1100, 0] + "position": [1180, 0] + }, + { + "parameters": { + "jsCode": "return $input.all().map((item) => {\n const row = item.json || {};\n const nextRetryCount = Number(row.retryCount || 0) + 1;\n const retryFeedback = (row.validationErrors || []).join(' | ');\n\n return {\n json: {\n ...row,\n retryCount: nextRetryCount,\n retryFeedback\n }\n };\n});" + }, + "id": "increment-retry", + "name": "Increment Retry", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [1400, -120] + }, + { + "parameters": { + "conditions": { + "boolean": [ + { + "value1": "={{$json.shouldExecute}}", + "value2": true + } + ] + } + }, + "id": "execute-needed", + "name": "Execute Needed?", + "type": "n8n-nodes-base.if", + "typeVersion": 2, + "position": [1400, 120] }, { "parameters": { @@ -96,50 +143,225 @@ "url": "={{$env.SITE_BASE_URL}}/api/tags/maintenance", "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n \"apiKey\": \"{{$env.WEBHOOK_API_KEY}}\",\n \"updates\": {{JSON.stringify($json.updates)}},\n \"merges\": {{JSON.stringify($json.merges)}}\n}", + "jsonBody": "={\n \"apiKey\": \"{{$env.WEBHOOK_API_KEY}}\",\n \"updates\": {{JSON.stringify($json.validated.updates || [])}},\n \"merges\": {{JSON.stringify($json.validated.merges || [])}}\n}", "options": {} }, "id": "execute-maintenance", "name": "Execute Maintenance", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, - "position": [1320, -100] + "position": [1620, 20], + "continueOnFail": true }, { "parameters": { - "jsCode": "const maintenanceResult = $('Execute Maintenance').first()?.json || {};\nconst skipped = $('Check Skip').first()?.json?.skipped;\n\nif (skipped) {\n return [{ json: {\n status: 'skipped',\n message: 'No changes needed',\n timestamp: new Date().toISOString()\n }}];\n}\n\nconst result = maintenanceResult.result || {};\n\nreturn [{ json: {\n status: maintenanceResult.success ? 'success' : 'failed',\n updatedCount: result.updatedCount || 0,\n mergedCount: result.mergedCount || 0,\n deletedTagCount: result.deletedTagCount || 0,\n timestamp: new Date().toISOString(),\n error: maintenanceResult.error || null\n}}];" + "jsCode": "return $input.all().map((item) => {\n const row = item.json || {};\n return {\n json: {\n status: row.status || 'noop',\n chunkId: row.chunkId || null,\n retryCount: Number(row.retryCount || 0),\n validationErrors: row.validationErrors || [],\n updatedCount: 0,\n mergedCount: 0,\n deletedTagCount: 0\n }\n };\n});" }, - "id": "summarize", + "id": "build-skip-result", + "name": "Build Skipped Result", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [1620, 220] + }, + { + "parameters": { + "jsCode": "return $input.all().map((item) => {\n const row = item.json || {};\n\n if (row.success === true) {\n return {\n json: {\n status: 'executed',\n chunkId: null,\n retryCount: null,\n validationErrors: [],\n updatedCount: Number(row?.result?.updatedCount || 0),\n mergedCount: Number(row?.result?.mergedCount || 0),\n deletedTagCount: Number(row?.result?.deletedTagCount || 0)\n }\n };\n }\n\n const message = row?.error?.message || row?.message || row?.error || 'Unknown execution error';\n\n return {\n json: {\n status: 'failed_execute',\n chunkId: null,\n retryCount: null,\n validationErrors: [String(message)],\n updatedCount: 0,\n mergedCount: 0,\n deletedTagCount: 0\n }\n };\n});" + }, + "id": "normalize-execution", + "name": "Normalize Execution Result", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [1840, 20] + }, + { + "parameters": { + "mode": "append" + }, + "id": "merge-results", + "name": "Merge Results", + "type": "n8n-nodes-base.merge", + "typeVersion": 3.2, + "position": [2060, 120] + }, + { + "parameters": { + "jsCode": "const rows = $input.all().map((item) => item.json || {});\n\nconst summary = {\n status: 'success',\n chunkRuns: rows.length,\n executedRuns: 0,\n noopRuns: 0,\n retryRuns: 0,\n failedValidationRuns: 0,\n failedExecuteRuns: 0,\n updatedCount: 0,\n mergedCount: 0,\n deletedTagCount: 0,\n failures: [],\n timestamp: new Date().toISOString()\n};\n\nfor (const row of rows) {\n if (row.status === 'executed') {\n summary.executedRuns += 1;\n summary.updatedCount += Number(row.updatedCount || 0);\n summary.mergedCount += Number(row.mergedCount || 0);\n summary.deletedTagCount += Number(row.deletedTagCount || 0);\n continue;\n }\n\n if (row.status === 'noop') {\n summary.noopRuns += 1;\n continue;\n }\n\n if (row.status === 'retry') {\n summary.retryRuns += 1;\n continue;\n }\n\n if (row.status === 'failed_validation') {\n summary.failedValidationRuns += 1;\n summary.failures.push({\n type: 'failed_validation',\n chunkId: row.chunkId || null,\n reasons: row.validationErrors || []\n });\n continue;\n }\n\n if (row.status === 'failed_execute') {\n summary.failedExecuteRuns += 1;\n summary.failures.push({\n type: 'failed_execute',\n chunkId: row.chunkId || null,\n reasons: row.validationErrors || []\n });\n }\n}\n\nif (summary.failedValidationRuns > 0 || summary.failedExecuteRuns > 0) {\n summary.status = 'partial_failed';\n}\n\nsummary.failures = summary.failures.slice(0, 20);\n\nreturn [{ json: summary }];" + }, + "id": "summarize-results", "name": "Summarize Results", "type": "n8n-nodes-base.code", "typeVersion": 2, - "position": [1540, 0] + "position": [2280, 120] } ], "connections": { "Daily 3AM UTC": { - "main": [[{ "node": "Fetch Tags", "type": "main", "index": 0 }]] + "main": [ + [ + { + "node": "Fetch Tags", + "type": "main", + "index": 0 + } + ] + ] }, "Fetch Tags": { - "main": [[{ "node": "Preprocess Tags", "type": "main", "index": 0 }]] - }, - "Preprocess Tags": { - "main": [[{ "node": "AI Analyze Tags", "type": "main", "index": 0 }]] - }, - "AI Analyze Tags": { - "main": [[{ "node": "Validate JSON", "type": "main", "index": 0 }]] - }, - "Validate JSON": { - "main": [[{ "node": "Check Skip", "type": "main", "index": 0 }]] - }, - "Check Skip": { "main": [ - [{ "node": "Execute Maintenance", "type": "main", "index": 0 }], - [{ "node": "Summarize Results", "type": "main", "index": 0 }] + [ + { + "node": "Prepare Chunk Batches", + "type": "main", + "index": 0 + } + ] + ] + }, + "Prepare Chunk Batches": { + "main": [ + [ + { + "node": "Tag Merge Agent", + "type": "main", + "index": 0 + } + ] + ] + }, + "OpenAI Chat Model": { + "ai_languageModel": [ + [ + { + "node": "Tag Merge Agent", + "type": "ai_languageModel", + "index": 0 + } + ] + ] + }, + "Structured Output Parser": { + "ai_outputParser": [ + [ + { + "node": "Tag Merge Agent", + "type": "ai_outputParser", + "index": 0 + } + ] + ] + }, + "Tag Merge Agent": { + "main": [ + [ + { + "node": "Validate Plan", + "type": "main", + "index": 0 + } + ] + ] + }, + "Validate Plan": { + "main": [ + [ + { + "node": "Retry Needed?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Retry Needed?": { + "main": [ + [ + { + "node": "Increment Retry", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Execute Needed?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Increment Retry": { + "main": [ + [ + { + "node": "Tag Merge Agent", + "type": "main", + "index": 0 + } + ] + ] + }, + "Execute Needed?": { + "main": [ + [ + { + "node": "Execute Maintenance", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Build Skipped Result", + "type": "main", + "index": 0 + } + ] ] }, "Execute Maintenance": { - "main": [[{ "node": "Summarize Results", "type": "main", "index": 0 }]] + "main": [ + [ + { + "node": "Normalize Execution Result", + "type": "main", + "index": 0 + } + ] + ] + }, + "Normalize Execution Result": { + "main": [ + [ + { + "node": "Merge Results", + "type": "main", + "index": 0 + } + ] + ] + }, + "Build Skipped Result": { + "main": [ + [ + { + "node": "Merge Results", + "type": "main", + "index": 1 + } + ] + ] + }, + "Merge Results": { + "main": [ + [ + { + "node": "Summarize Results", + "type": "main", + "index": 0 + } + ] + ] } }, "settings": { diff --git a/src/app/api/discovery/lib/discovery-service.ts b/src/app/api/discovery/lib/discovery-service.ts index da7a04d..82b9d9a 100644 --- a/src/app/api/discovery/lib/discovery-service.ts +++ b/src/app/api/discovery/lib/discovery-service.ts @@ -1,6 +1,166 @@ import { prisma } from '@/lib/prisma' import type { ProjectInput } from '@/lib/validations' import { generateSlug } from '@/lib/slug' +import type { Prisma } from '@prisma/client' + +const PLURAL_NORMALIZATION_MAP = new Map([ + ['agents', 'agent'], + ['assistants', 'assistant'], + ['tools', 'tool'], + ['frameworks', 'framework'], + ['models', 'model'], + ['servers', 'server'], + ['clients', 'client'], + ['workflows', 'workflow'], + ['plugins', 'plugin'], + ['libraries', 'library'], + ['datasets', 'dataset'], + ['platforms', 'platform'], + ['systems', 'system'], + ['repositories', 'repository'], + ['engines', 'engine'], +]) + +const NOISE_TAG_KEYS = new Set([ + 'ai', + 'artificial intelligence', + 'open source', + 'requires configuration', + 'requires basics', + 'low learning curve', + 'enterprise', + 'complex deployment', + 'cloud service', + 'cross platform', + 'tutorial', + 'academic research', + 'academic resource', + 'ai research resource', + 'multi language support', + 'self hosted', + 'user notification', + 'mit license', + 'apache 2 0', + '开源', + '需要配置', + '需要基础', + '低学习成本', + '企业级', + '复杂部署', + '云端服务', + '跨平台', + '教程', + '学术研究', + '学术资源', + '多语言支持', + '自托管', + '用户通知', + '许可', +]) + +const TAG_FALLBACK = { + name: 'AI开发工具', + nameEn: 'AI Development Tool', +} as const + +function normalizeWhitespace(value: string): string { + return value.replace(/\s+/g, ' ').trim() +} + +function isAsciiText(value: string): boolean { + return /^[\x00-\x7f]+$/.test(value) +} + +function canonicalizeTagKey(value: string): string { + const normalized = normalizeWhitespace(value) + .normalize('NFKC') + .toLowerCase() + .replace(/[+/_&|-]+/g, ' ') + .replace(/[^a-z0-9\u4e00-\u9fa5\s]/g, ' ') + .replace(/\s+/g, ' ') + .trim() + + if (!normalized) { + return '' + } + + return normalized + .split(' ') + .map((word) => PLURAL_NORMALIZATION_MAP.get(word) || word) + .join(' ') + .trim() +} + +function normalizeIncomingTag(tag: ProjectInput['tags'][number]) { + const normalizedName = normalizeWhitespace(tag.name) + const normalizedNameEn = normalizeWhitespace(tag.nameEn || '') + const resolvedNameEn = normalizedNameEn || (isAsciiText(normalizedName) ? normalizedName : '') + const canonicalNameKey = canonicalizeTagKey(normalizedName) + const canonicalNameEnKey = canonicalizeTagKey(resolvedNameEn) + + return { + name: normalizedName, + nameEn: resolvedNameEn || null, + canonicalNameKey, + canonicalNameEnKey, + slug: generateSlug(normalizedName, resolvedNameEn || null), + } +} + +function isMeaningfulTag(tag: ReturnType): boolean { + if (!tag.name) { + return false + } + + if (NOISE_TAG_KEYS.has(tag.canonicalNameKey)) { + return false + } + + if (tag.canonicalNameEnKey && NOISE_TAG_KEYS.has(tag.canonicalNameEnKey)) { + return false + } + + return true +} + +type TagWithProjectCount = Prisma.TagGetPayload<{ + include: { + _count: { select: { projects: true } } + } +}> + +function chooseBestTag(candidates: TagWithProjectCount[]): TagWithProjectCount { + return [...candidates].sort((a, b) => { + const projectDiff = b._count.projects - a._count.projects + if (projectDiff !== 0) { + return projectDiff + } + return a.createdAt.getTime() - b.createdAt.getTime() + })[0]! +} + +async function getFallbackTag(): Promise { + const fallbackSlug = generateSlug(TAG_FALLBACK.name, TAG_FALLBACK.nameEn) + const fallbackTag = await prisma.tag.upsert({ + where: { slug: fallbackSlug }, + update: { + name: TAG_FALLBACK.name, + nameEn: TAG_FALLBACK.nameEn, + }, + create: { + name: TAG_FALLBACK.name, + nameEn: TAG_FALLBACK.nameEn, + slug: fallbackSlug, + }, + include: { + _count: { + select: { projects: true }, + }, + }, + }) + + return fallbackTag +} /** * 多级去重策略:查找已存在的项目 @@ -90,44 +250,159 @@ export async function findExistingProject(projectData: ProjectInput) { * @returns 标签连接对象数组 */ export async function upsertTags(tags: ProjectInput['tags']) { - // 优化:批量查询所有已存在的标签,避免 N+1 问题 - const allTagNames = tags.map((t) => t.name) + const meaningfulTags = tags + .map((tag) => normalizeIncomingTag(tag)) + .filter((tag) => isMeaningfulTag(tag)) + + const normalizedIncomingTags = Array.from( + new Map( + meaningfulTags.map((normalized) => { + return [ + normalized.canonicalNameEnKey || normalized.canonicalNameKey || normalized.name, + normalized, + ] as const + }) + ).values() + ) + + if (normalizedIncomingTags.length === 0) { + return [await getFallbackTag()] + } + const existingTags = await prisma.tag.findMany({ - where: { name: { in: allTagNames } }, + include: { + _count: { + select: { projects: true }, + }, + }, }) - const existingTagNames = new Set(existingTags.map((t) => t.name)) - // Upsert tags - 优化后只查询不存在的标签 - return await Promise.all( - tags.map(async (tag) => { - const tagSlug = generateSlug(tag.name, tag.nameEn) + const tagByExactName = new Map() + const tagBySlug = new Map() + const tagByCanonicalName = new Map() + const tagByCanonicalNameEn = new Map() - // 首先从批量查询结果中查找 - if (existingTagNames.has(tag.name)) { - return existingTags.find((t) => t.name === tag.name)! + for (const tag of existingTags) { + const exactNameKey = normalizeWhitespace(tag.name) + const existingCanonicalName = canonicalizeTagKey(tag.name) + const existingCanonicalNameEn = canonicalizeTagKey(tag.nameEn || '') + + if (!tagByExactName.has(exactNameKey)) { + tagByExactName.set(exactNameKey, []) + } + tagByExactName.get(exactNameKey)!.push(tag) + + if (existingCanonicalName) { + if (!tagByCanonicalName.has(existingCanonicalName)) { + tagByCanonicalName.set(existingCanonicalName, []) } + tagByCanonicalName.get(existingCanonicalName)!.push(tag) + } - // 只有标签不存在时才尝试 upsert - try { - return await prisma.tag.upsert({ - where: { slug: tagSlug }, - update: {}, - create: { - name: tag.name, - nameEn: tag.nameEn || null, - slug: tagSlug, - }, + if (existingCanonicalNameEn) { + if (!tagByCanonicalNameEn.has(existingCanonicalNameEn)) { + tagByCanonicalNameEn.set(existingCanonicalNameEn, []) + } + tagByCanonicalNameEn.get(existingCanonicalNameEn)!.push(tag) + } + + tagBySlug.set(tag.slug, tag) + } + + const resolvedTags: TagWithProjectCount[] = [] + + for (const incomingTag of normalizedIncomingTags) { + const exactNameCandidates = tagByExactName.get(incomingTag.name) || [] + let matchedTag = exactNameCandidates.length > 0 ? chooseBestTag(exactNameCandidates) : null + + if (!matchedTag && incomingTag.canonicalNameKey) { + const canonicalNameCandidates = tagByCanonicalName.get(incomingTag.canonicalNameKey) || [] + if (canonicalNameCandidates.length > 0) { + matchedTag = chooseBestTag(canonicalNameCandidates) + } + } + + if (!matchedTag && incomingTag.canonicalNameEnKey) { + const canonicalNameEnCandidates = tagByCanonicalNameEn.get(incomingTag.canonicalNameEnKey) || [] + if (canonicalNameEnCandidates.length > 0) { + matchedTag = chooseBestTag(canonicalNameEnCandidates) + } + } + + if (!matchedTag) { + matchedTag = tagBySlug.get(incomingTag.slug) || null + } + + if (matchedTag) { + if (incomingTag.nameEn && !matchedTag.nameEn) { + await prisma.tag.update({ + where: { id: matchedTag.id }, + data: { nameEn: incomingTag.nameEn }, }) - } catch (error) { - // 如果 slug 冲突,查找并使用已存在的标签 - const existingBySlug = await prisma.tag.findUnique({ - where: { slug: tagSlug }, - }) - if (existingBySlug) { - return existingBySlug + matchedTag = { + ...matchedTag, + nameEn: incomingTag.nameEn, } - throw error } - }) + + resolvedTags.push(matchedTag) + continue + } + + try { + const createdTag = await prisma.tag.create({ + data: { + name: incomingTag.name, + nameEn: incomingTag.nameEn, + slug: incomingTag.slug, + }, + include: { + _count: { + select: { projects: true }, + }, + }, + }) + resolvedTags.push(createdTag) + + if (!tagByExactName.has(createdTag.name)) { + tagByExactName.set(createdTag.name, []) + } + tagByExactName.get(createdTag.name)!.push(createdTag) + tagBySlug.set(createdTag.slug, createdTag) + if (createdTag.nameEn) { + const canonicalNameEn = canonicalizeTagKey(createdTag.nameEn) + if (canonicalNameEn) { + if (!tagByCanonicalNameEn.has(canonicalNameEn)) { + tagByCanonicalNameEn.set(canonicalNameEn, []) + } + tagByCanonicalNameEn.get(canonicalNameEn)!.push(createdTag) + } + } + } catch { + const fallbackTag = await prisma.tag.findFirst({ + where: { + OR: [ + { name: incomingTag.name }, + { slug: incomingTag.slug }, + ], + }, + include: { + _count: { + select: { projects: true }, + }, + }, + }) + + if (fallbackTag) { + resolvedTags.push(fallbackTag) + continue + } + + throw new Error(`Failed to resolve tag: ${incomingTag.name}`) + } + } + + return Array.from( + new Map(resolvedTags.map((tag) => [tag.id, tag])).values() ) } diff --git a/src/app/api/webhook/projects/route.ts b/src/app/api/webhook/projects/route.ts index a8bd58a..c51bd1c 100644 --- a/src/app/api/webhook/projects/route.ts +++ b/src/app/api/webhook/projects/route.ts @@ -8,7 +8,7 @@ import { type WebhookPayload, type ProjectInput, } from '@/lib/validations' -import { findExistingProject } from '../../discovery/lib/discovery-service' +import { findExistingProject, upsertTags } from '../../discovery/lib/discovery-service' import { generateSlug } from '@/lib/slug' export async function POST(request: NextRequest) { @@ -90,46 +90,8 @@ export async function POST(request: NextRequest) { // 多级去重:查找已存在的项目 const existingProject = await findExistingProject(validProject) - // 优化:批量查询所有已存在的标签,避免 N+1 问题 - const allTagNames = validProject.tags.map((t) => t.name) - const existingTags = await prisma.tag.findMany({ - where: { name: { in: allTagNames } }, - }) - const existingTagNames = new Set(existingTags.map((t) => t.name)) - - // Upsert tags - 优化后只查询不存在的标签 - const tagConnections = await Promise.all( - validProject.tags.map(async (tag) => { - const tagSlug = generateSlug(tag.name, tag.nameEn) - - // 首先从批量查询结果中查找 - if (existingTagNames.has(tag.name)) { - return existingTags.find((t) => t.name === tag.name)! - } - - // 只有标签不存在时才尝试 upsert - try { - return await prisma.tag.upsert({ - where: { slug: tagSlug }, - update: {}, - create: { - name: tag.name, - nameEn: tag.nameEn || null, - slug: tagSlug, - }, - }) - } catch (error) { - // 如果 slug 冲突,查找并使用已存在的标签 - const existingBySlug = await prisma.tag.findUnique({ - where: { slug: tagSlug }, - }) - if (existingBySlug) { - return existingBySlug - } - throw error - } - }) - ) + // 标签规范化与自动复用(防止同义标签持续膨胀) + const tagConnections = await upsertTags(validProject.tags) // Generate slug for project const slug = generateSlug(validProject.name, validProject.nameEn)