fdbw commited on
Commit
d96b2d8
·
verified ·
1 Parent(s): 4f3bd16

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -0
app.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from collections import deque
4
+
5
+ # 尝试导入 streamlit
6
+ try:
7
+ import streamlit as st
8
+ except ImportError:
9
+ # 仅用于本地调试提示
10
+ print("Streamlit 模块未找到,请确保在 Hugging Face Streamlit 环境下运行")
11
+ os._exit(1)
12
+
13
+ # --- 核心数据逻辑 ---
14
+ class FamilySystem:
15
+ def __init__(self, data_file='family_data.jsonl'):
16
+ self.people = {}
17
+ # 确保数据文件名与您上传的一致
18
+ self.load_data(data_file)
19
+
20
+ def load_data(self, path):
21
+ if not os.path.exists(path):
22
+ st.error(f"❌ 找不到数据文件: {path}")
23
+ return
24
+ try:
25
+ with open(path, 'r', encoding='utf-8') as f:
26
+ for line in f:
27
+ line = line.strip()
28
+ if not line: continue
29
+ # 使用最安全的方式解析 JSON,避开所有正则转义陷阱
30
+ try:
31
+ item = json.loads(line)
32
+ if 'n' in item:
33
+ self.people[item['n']] = item
34
+ except:
35
+ continue
36
+ if self.people:
37
+ st.sidebar.success(f"✅ 已加载 {len(self.people)} 位家族成员")
38
+ except Exception as e:
39
+ st.error(f"加载失败: {str(e)}")
40
+
41
+ def get_path(self, start, end):
42
+ """跨树 BFS 路径搜索"""
43
+ if start not in self.people or end not in self.people: return None
44
+ queue = deque([(start, [])])
45
+ visited = {start}
46
+ while queue:
47
+ curr, path = queue.popleft()
48
+ if curr == end: return path + [curr]
49
+ p = self.people.get(curr, {})
50
+ neighbors = []
51
+ if p.get('f'): neighbors.append(p['f'])
52
+ if p.get('m'): neighbors.append(p['m'])
53
+ sp = p.get('sp', [])
54
+ if isinstance(sp, list): neighbors.extend(sp)
55
+ else: neighbors.append(sp)
56
+ # 反向找子女
57
+ for name, data in self.people.items():
58
+ if data.get('f') == curr or data.get('m') == curr:
59
+ neighbors.append(name)
60
+ for nbor in set(neighbors):
61
+ if nbor and nbor not in visited and nbor in self.people:
62
+ visited.add(nbor)
63
+ queue.append((nbor, path + [curr]))
64
+ return None
65
+
66
+ # --- UI 渲染部分 ---
67
+ # st.set_page_config 必须是第一个调用的 streamlit 命令
68
+ st.set_page_config(page_title="家族网查询系统", layout="wide")
69
+
70
+ @st.cache_resource
71
+ def init_system():
72
+ return FamilySystem()
73
+
74
+ sys = init_system()
75
+
76
+ st.title("🌳 家族亲属关系查询系统")
77
+
78
+ tab1, tab2, tab3 = st.tabs(["👤 个人档案", "🕸️ 族网推演", "🔍 关系查询"])
79
+
80
+ with tab1:
81
+ name = st.text_input("输入姓名查询:", placeholder="冯宗德")
82
+ if name in sys.people:
83
+ p = sys.people[name]
84
+ col1, col2 = st.columns([1, 2])
85
+ with col1:
86
+ photo = f"photos/{name}.jpg"
87
+ if os.path.exists(photo): st.image(photo)
88
+ else: st.info("📷 暂无照片")
89
+ with col2:
90
+ st.subheader(f"{name} ({p.get('s','?')})")
91
+ st.write(f"**父/母**:{p.get('f','-')} / {p.get('m','-')}")
92
+ st.info(f"**生卒信息**:{p.get('info','')}")
93
+ elif name:
94
+ st.error("查无此人")
95
+
96
+ with tab2:
97
+ st.write("### 20种关系推演")
98
+ st.caption("该模块将根据《中国亲属称呼精准精简版》逻辑生成。")
99
+
100
+ with tab3:
101
+ st.subheader("分析两人关系路径")
102
+ n1 = st.text_input("起始人", value="冯宗德")
103
+ n2 = st.text_input("目标人", value="沈兴华")
104
+ if st.button("开始分析路径"):
105
+ path = sys.get_path(n1, n2)
106
+ if path:
107
+ st.success("🔗 发现连接:")
108
+ st.code(" → ".join(path))
109
+ else:
110
+ st.error("路径不通,未发现关联")
111
+
112
+ st.divider()
113
+ st.caption("项目约定:基于 n.f.m.sp 结构推演 | 忽略 g 字段")