Download app.py from fdbw/fzd14: direct link, hf CLI and curl.
- Browser
- Download file 4.03 kB
-
https://huggingface.co/spaces/fdbw/fzd14/resolve/main/app.py
- Command line
-
hf download hf://spaces/fdbw/fzd14/app.py
-
curl -L -o app.py https://huggingface.co/spaces/fdbw/fzd14/resolve/main/app.py
4.03 kB
| 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") | |
| 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 字段") |