import os import json from collections import deque # 尝试导入 streamlit 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 # 使用最安全的方式解析 JSON,避开所有正则转义陷阱 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 # --- UI 渲染部分 --- # st.set_page_config 必须是第一个调用的 streamlit 命令 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 字段")