📦 Narrative TopologyExtract — 叙事拓扑提取
v1.0.0擅长从长篇叙事、架构或复杂讨论中抽取语义关系,并以RDF三元组形式建模,随后生成邻接矩阵重构信息结构。
详细分析 ▾
运行时依赖
版本
narrative-topology 技能初始发布。 - 引入 RDF 风格三元组表示,用于从叙事中提取语义。 - 提供 Python 扫描器,提取并扩展三元组,生成邻接矩阵。 - 支持并行主语/宾语,使用笛卡尔积表示。 - 输出压缩邻接矩阵及基础叙事图统计。 - 支持下游图分析(度、路径、环)以处理复杂讨论。 - 包含扩展输出至加权边及生成 Mermaid 图的说明。
安装命令
点击复制技能文档
核心概念
问题: 长讨论(100+ 消息、架构辩论、叙事分析)失去结构,容易遗漏关键依赖、因果链或瓶颈。 解决方案: 在 markdown 中嵌入 RDF 风格三元组,用 Python 扫描,提取语义邻接矩阵,一眼看清结构。---
三元组语法
格式
``
<<{Subject, Predicate, Object}.
` 示例
简单关系:
`
<<{Claude, outputs, analysis}.
<<{analysis, informs, decision}.
` 并行主语(笛卡尔积):
`
<<{[A, B, C], implements, feature}.
`
展开为:
`
{A, implements, feature}
{B, implements, feature}
{C, implements, feature}
`
并行宾语:
`
<<{payment_system, affects, [latency, cost, security]}.
`
两者并行:
`
<<{[Claude, User], collaborated_on, [design, implementation]}.
`
全笛卡尔积:2×2 = 4 条边。
语法规则
<<{开始三元组}.(点号)结束- 逗号分隔主语、谓语、宾语
- 自动去除空白
[...]表示列表;裸词为单例- 置于 markdown 行内,易 grep
为何选此格式
- 类 RDF——语义网标准,易懂
易 grep——grep '<<{' file.md找出全部三元组- 无歧义——起止清晰,无嵌套
- 原生 Markdown——不破坏渲染
- 紧凑——一行一关系
---
示例:哈姆雷特
输入 markdown(节选):
`markdown
Act I
<<{Claudius, murders, old_king}.
<<{Claudius, usurps, Denmark_throne}.
<<{Claudius, marries, Gertrude}.
Act II
<<{ghost, reveals, Hamlet}.
<<{ghost, demands, revenge}.
<<{Hamlet, feigns, madness}.
<<{Hamlet, kills, Polonius}.
Consequences
<<{Polonius_death, causes, Ophelia_madness}.
<<{Ophelia, drowns, river}.
Climax
<<{[Hamlet, Laertes], duel, each_other}.
<<{[poison_sword, poison_wine], kills, [Hamlet, Laertes, Claudius, Gertrude]}.
<<{Fortinbras, takes_over, Denmark}.
`
输出:邻接矩阵,展示 14 个节点及其因果/叙事依赖。 ---
Python 扫描器
把 scanner.py 放入 markdown 目录,运行:
`bash
python scanner.py
`
代码
`python
#!/usr/bin/env python3
"""
Narrative Topology Scanner
Usage: python scanner.py
输出 x::n 压缩格式的邻接矩阵
"""
import os
import sys
def list_files_recursive(directory, extensions=('.txt', '.def', '.erl', '.ex', '.md')):
for root, _, files in os.walk(directory):
for f in files:
if f.endswith(extensions):
yield os.path.join(root, f)
def parse_list(s):
s = s.strip()
if s.startswith('[') and s.endswith(']'):
inner = s[1:-1].strip()
if not inner:
return []
return [item.strip() for item in inner.split(',')]
return [s]
def smart_split(content):
parts, current, depth = [], [], 0
for ch in content:
if ch == ',' and depth == 0:
parts.append(''.join(current).strip())
current = []
else:
if ch == '[':
depth += 1
elif ch == ']':
depth -= 1
current.append(ch)
if current:
parts.append(''.join(current).strip())
return parts if len(parts) == 3 else None
def process_line(line):
line = line.strip()
if not line.startswith('<<{'):
return []
if not line.endswith('}.'):
return []
content = line[3:-2]
parts = smart_split(content)
if not parts:
return []
s, p, o = parts
subjects = parse_list(s)
objects = parse_list(o)
edges = []
for subj in subjects:
for obj in objects:
edges.append((subj, obj))
return edges
def process_file(filepath):
edges = []
try:
with open(filepath, 'r', encoding='utf-8') as f:
for line in f:
edges.extend(process_line(line))
except Exception:
pass
``