feat: add dingtalk-feishu-collector SOP skill
Reusable 6-step pipeline for collecting DingTalk group messages, extracting Feishu doc links, fetching content, and generating summaries. Skills structure: - SKILL.md: trigger rules, workflow, config reference - config.yaml: group IDs, collection settings - scripts/paths.py: shared path resolution - scripts/step1-6: modular pipeline steps - scripts/run_all.py: one-click runner
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""Step 6: 更新知识库(Obsidian + 知识图谱)"""
|
||||
import json, os, sys
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from paths import LINKS_DIR, DATA_DIR, DOCS_DIR, OBSIDIAN_DIR, KG_DIR
|
||||
|
||||
def safe_name(n):
|
||||
for c in '<>:"/\\|?*': n=n.replace(c,'_')
|
||||
return n[:80]
|
||||
|
||||
def w(path, content):
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path,"w",encoding="utf-8") as f: f.write(content)
|
||||
|
||||
def load_json(p):
|
||||
if not os.path.isfile(p): return None
|
||||
with open(p,"r",encoding="utf-8") as f: return json.load(f)
|
||||
|
||||
def main():
|
||||
content = load_json(os.path.join(LINKS_DIR,"all_feishu_content.json")) or {}
|
||||
messages = load_json(os.path.join(DATA_DIR,"raw-messages","all_messages_combined.json")) or {}
|
||||
docs = content.get("documents",[])
|
||||
|
||||
print(f"文档: {len(docs)}, 消息: {sum(len(v) for v in messages.values())}")
|
||||
|
||||
# Obsidian
|
||||
by_group = defaultdict(list)
|
||||
for d in docs: by_group[d.get("group","未分组")].append(d)
|
||||
by_sender = defaultdict(list)
|
||||
for d in docs: by_sender[d.get("sender","?")].append(d)
|
||||
|
||||
moc = ["---","tags: [MOC, 飞书文档]",f"created: {datetime.now().strftime('%Y-%m-%d')}","---","","# 飞书文档知识库","",f"> 更新: {datetime.now().strftime('%Y-%m-%d %H:%M')}",""]
|
||||
for grp, gd in sorted(by_group.items()):
|
||||
moc.append(f"## {grp}")
|
||||
for d in sorted(gd,key=lambda x:x.get("time",""),reverse=True):
|
||||
t = d.get("title","") or d.get("doc_id","")
|
||||
moc.append(f"- [[{safe_name(t)}]] ({d.get('sender','?')}, {d.get('time','')})")
|
||||
moc.append("")
|
||||
w(os.path.join(OBSIDIAN_DIR,"00-MOC","飞书文档索引.md"),"\n".join(moc))
|
||||
|
||||
for sender, sd in sorted(by_sender.items()):
|
||||
lines = ["---",f"tags: [人物, {sender}]","---",f"# {sender}",f"\n贡献: {len(sd)} 篇\n"]
|
||||
for d in sorted(sd,key=lambda x:x.get("time",""),reverse=True):
|
||||
t = d.get("title","") or d.get("doc_id","")
|
||||
lines.append(f"- [[{safe_name(t)}]] ({d.get('time','')})")
|
||||
w(os.path.join(OBSIDIAN_DIR,"04-人物",f"{safe_name(sender)}.md"),"\n".join(lines))
|
||||
|
||||
for d in docs:
|
||||
did = d.get("doc_id","")
|
||||
fpath = os.path.join(DOCS_DIR,f"{did}.md")
|
||||
if not os.path.isfile(fpath): continue
|
||||
with open(fpath,"r",encoding="utf-8") as f: c = f.read()
|
||||
t = d.get("title","") or did
|
||||
fm = ["---",f"tags: [飞书文档, {d.get('group','')}]",f"sender: {d.get('sender','')}",f"date: {d.get('time','')}",f"source: {d.get('url','')}","---",""]
|
||||
w(os.path.join(OBSIDIAN_DIR,"01-产品研究",f"{safe_name(t)}.md"),"\n".join(fm)+c)
|
||||
print(f" Obsidian: {len(docs)} 文档, {len(by_sender)} 人物")
|
||||
|
||||
# 知识图谱
|
||||
nodes, edges, nids = [], [], set()
|
||||
for s in {d.get("sender","") for d in docs} | {m.get("sender","") for msgs in messages.values() for m in msgs}:
|
||||
if s: nid=f"person:{s}"; nodes.append({"id":nid,"type":"person","label":s}); nids.add(nid)
|
||||
for d in docs:
|
||||
did,t = d.get("doc_id",""), d.get("title","") or d.get("doc_id","")
|
||||
nid = f"doc:{did}"
|
||||
if nid not in nids: nodes.append({"id":nid,"type":"document","label":t[:50]}); nids.add(nid)
|
||||
s = d.get("sender","")
|
||||
if s: edges.append({"source":f"person:{s}","target":nid,"type":"authored"})
|
||||
g = d.get("group","")
|
||||
if g:
|
||||
gid=f"group:{g}"
|
||||
if gid not in nids: nodes.append({"id":gid,"type":"group","label":g}); nids.add(gid)
|
||||
edges.append({"source":gid,"target":nid,"type":"contains"})
|
||||
os.makedirs(KG_DIR, exist_ok=True)
|
||||
with open(os.path.join(KG_DIR,"knowledge_graph.json"),"w",encoding="utf-8") as f:
|
||||
json.dump({"date":datetime.now().strftime("%Y-%m-%d"),"nodes":nodes,"edges":edges},f,ensure_ascii=False,indent=2)
|
||||
print(f" 图谱: {len(nodes)} 节点, {len(edges)} 关系")
|
||||
|
||||
if __name__ == "__main__": main()
|
||||
Reference in New Issue
Block a user