| import os |
| import json |
| from collections import deque |
|
|
| |
| try: |
| import streamlit as st |
| except ImportError: |
| |
| print("Streamlit 模块未找到,请确保在 Hugging Face Streamlit 环境下运行") |
| os._exit(1) |
|
|
| |
| class FamilySystem: |
| def __init__(self, data_file='family_data.jsonl'): |
| self.people = {} |
| |
| self.load_data(data_file) |
|
|
| def load_data(self, path): |
| if not os.path.exists(path): |
| st.error(f"❌ 找不到数据文件: {path}") |
| return |
| try: |
| with open(path, 'r', encoding='utf-8') as f: |
| for line in f: |
| line = line.strip() |
| if not line: continue |
| |
| try: |
| item = json.loads(line) |
| if 'n' in item: |
| self.people[item['n']] = item |
| except: |
| continue |
| if self.people: |
| st.sidebar.success(f"✅ 已加载 {len(self.people)} 位家族成员") |
| except Exception as e: |
| st.error(f"加载失败: {str(e)}") |
|
|
| def get_path(self, start, end): |
| """跨树 BFS 路径搜索""" |
| if start not in self.people or end not in self.people: return None |
| queue = deque([(start, [])]) |
| visited = {start} |
| while queue: |
| curr, path = queue.popleft() |
| if curr == end: return path + [curr] |
| p = self.people.get(curr, {}) |
| neighbors = [] |
| if p.get('f'): neighbors.append(p['f']) |
| if p.get('m'): neighbors.append(p['m']) |
| sp = p.get('sp', []) |
| if isinstance(sp, list): neighbors.extend(sp) |
| else: neighbors.append(sp) |
| |
| for name, data in self.people.items(): |
| if data.get('f') == curr or data.get('m') == curr: |
| neighbors.append(name) |
| for nbor in set(neighbors): |
| if nbor and nbor not in visited and nbor in self.people: |
| visited.add(nbor) |
| queue.append((nbor, path + [curr])) |
| return None |
|
|
| |
| |
| st.set_page_config(page_title="家族网查询系统", layout="wide") |
|
|
| @st.cache_resource |
| def init_system(): |
| return FamilySystem() |
|
|
| sys = init_system() |
|
|
| st.title("🌳 家族亲属关系查询系统") |
|
|
| tab1, tab2, tab3 = st.tabs(["👤 个人档案", "🕸️ 族网推演", "🔍 关系查询"]) |
|
|
| with tab1: |
| name = st.text_input("输入姓名查询:", placeholder="冯宗德") |
| if name in sys.people: |
| p = sys.people[name] |
| col1, col2 = st.columns([1, 2]) |
| with col1: |
| photo = f"photos/{name}.jpg" |
| if os.path.exists(photo): st.image(photo) |
| else: st.info("📷 暂无照片") |
| with col2: |
| st.subheader(f"{name} ({p.get('s','?')})") |
| st.write(f"**父/母**:{p.get('f','-')} / {p.get('m','-')}") |
| st.info(f"**生卒信息**:{p.get('info','')}") |
| elif name: |
| st.error("查无此人") |
|
|
| with tab2: |
| st.write("### 20种关系推演") |
| st.caption("该模块将根据《中国亲属称呼精准精简版》逻辑生成。") |
|
|
| with tab3: |
| st.subheader("分析两人关系路径") |
| n1 = st.text_input("起始人", value="冯宗德") |
| n2 = st.text_input("目标人", value="沈兴华") |
| if st.button("开始分析路径"): |
| path = sys.get_path(n1, n2) |
| if path: |
| st.success("🔗 发现连接:") |
| st.code(" → ".join(path)) |
| else: |
| st.error("路径不通,未发现关联") |
|
|
| st.divider() |
| st.caption("项目约定:基于 n.f.m.sp 结构推演 | 忽略 g 字段") |