# xiangqinlu **Repository Path**: lainyu/xiangqinlu ## Basic Information - **Project Name**: xiangqinlu - **Description**: 这是一款 AI driven 用于统计乡政府村名信息的微型 ETL web app。 用于解决:整理多年乡政府杂乱无章的 Excel,方便统计、搜索和管理乡民信息,并根据期望格式输出新类型的报告。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-05 - **Last Updated**: 2026-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # XIANG QIN LU 乡亲录 这是一款 AI driven 用于统计乡政府村名信息的微型 ETL web app。 用于解决:整理多年乡政府杂乱无章的 Excel,方便统计、搜索和管理乡民信息,并根据期望格式输出新类型的报告。 > 一句话:**多年积累的、格式乱七八糟的乡政府 Excel → 一个以身份证号为索引、可搜索、可追溯的数据库 → 按任意模板生成报告。** > AI 只负责"看懂表头、写规则",**数据本身全程由程序处理,每一步都由人在界面上确认**。可控、省钱、出错可排查。 > **开发方向说明:** 当前数据库仅为测试数据。后续按 > [数据模型改造开发文档.md](数据模型改造开发文档.md) 直接重建为“完整来源行 > JSON + `group_id` + 人物关联”模型,不兼容旧测试库。 ## 要解决的问题 1. 多年累积的不同格式、不同信息的 Excel 难以索引,需要人手逐个点开文件搜索。 2. 同一个村民的信息可能分散在不同的文件里,输出目标 report 时需要花很长时间收集不同类型的信息。 3. 表格格式不统一。每张表里都有姓名、身份证号、性别、联系电话等基础信息,但记录的类型可能是个人状态(教育、疾病、务工等)、医保、纠纷、扶贫(家庭收入、学业补助、养殖补助、交通补助等)、个人林地耕地、户籍关系、财产信息(宅基地、车产等),且同一个人的基础信息表头名字可能不一致。 4. 需求的报告表格必须按照给定的 template 填写,每一次可能都不一样。 5. **数据源很脏**:多层级联表头、盖章/标题/填报单位横幅、号称 100 万行其实只有几千行有内容、夹着只有一个重复名字的垃圾行、重复行、身份证写错…… ## 核心原则 | 原则 | 含义 | |---|---| | **AI 不碰数据** | AI 只生成"规则":列映射 JSON / 取数规则 / 只读 SELECT。发给 AI 的样例一律打码(身份证、电话、账号),只让它看结构 | | **人工确认关卡** | 任何 AI 生成的规则,都必须经人在界面上确认后才会被程序执行,没有绕过路径 | | **不静默丢数据** | 身份证不合格的行进"待修队列";脏数据迹象进"数据体检";跳过的行公示行号。**提示用户检查,而不是悄悄吞掉** | | **可追溯** | 每个有效 Excel 行只保存一次完整 JSON,并保留来源文件、Sheet、原行号和组号 | | **身份证号用于找人** | 合法身份证建立人物索引;无证或证件有误的来源行仍会保存,不强迫所有数据挂在人下面 | ## 功能一览 界面共六页(侧边栏切换),右上角 ⚙️ 可查看/修改发给 AI 的措辞(规则库)。 | 页面 | 做什么 | |---|---| | **数据导入** | 上传 `.xlsx` / `.xls` → 自动识别表头与数据区 → AI 起草分组、继承列和人员角色 → 人工确认 → 清洗入库。导入完成会汇报:来源行数、组数、关联人数、待修行、被跳过的行号和数据体检问题 | | **人物检索** | 万能搜索框:身份证 / 姓名 / 任意字段值。点进去看一个人跨所有来源文件的全部记录(按类别与来源分组,可看原始行) | | **找数据** | 库里到底有什么、在哪个文件、长什么样。**搜一搜**(列名/取值/文件名都搜)· **数据目录**(每张来源表每列的填充率、取值、范围)· **按模板找数据**(上传要填的模板,逐列推荐库里最像的来源列,并指出哪些列库里没有)· **数据体检**(逐条查看脏数据提示,标记"已看过") | | **报告导出** | **模板模式**:上传 template → AI 根据全部来源目录建议名单范围、输出粒度和多表取数规则 → 人工核对底稿 → 按原样式(含合并表头)写出 xlsx,缺失字段标黄;**问数模式(Text2SQL)**:自然语言提问 → AI 生成只读 SELECT → 结果在线查看 / 下载 | | **错误行修复** | 身份证有问题的行按表分组:15 位升 18 位、17 位补全、人工改号;也可批量忽略;疑难行可请 AI 解读(出入境均有 PII 终检) | | **设置** | 模型、API Key、连接测试、昼夜模式 | ## 界面 奶油白底 + 玫瑰粉,页首是手绘的比熊小狗,空状态配一张真实狗狗照片;深浅两种模式 各一套配色(设置页切换)。 - 颜色只有一个来源:`src/ui/palette.py`;样式只有一处注入点:`src/ui/theme.py`。 页面文件(`src/ui/page_*.py`)不写 CSS,只调用 `theme.page_header(...)` 这类成品组件。 - 想换狗:把 `src/ui/art/duty-01..04.jpg` 覆盖成自己的照片即可(440×440 的 JPEG 最省体积);页首插画由 `tools/make_mascot.py` 生成,改参数重跑即可。 - 图片必须留在 `src/` 下——发行包与升级只覆盖 `src/`。 ## 数据流 ```mermaid flowchart TD A[Excel .xlsx / .xls] --> B[解析:识别表头区与数据区] B --> C{表头指纹命中缓存?} C -- 是 --> E C -- 否 --> D[AI 起草列映射 样例已打码] D --> E[人工确认映射] E --> F[清洗:身份证 日期 电话] F --> G[(SQLite)] F --> H[待修队列] B --> I[数据体检] I --> G G --> J[人物检索] G --> K[找数据] G --> L[报告导出] ``` 导入时在**同一个事务**里写入:`import_file / source_sheet`(来源与规则)· `source_row`(每行一份完整 JSON)· `person / row_person`(人物索引与来源关联)· `repair_queue`(待修角色)· `data_issues`(体检结果)· 映射和列统计缓存。同一户或 连续数据块通过 `group_id` 关联,不再拆成长表,也不为每个 Sheet 新建数据库表。 ## 处理"很脏的数据源" | 问题 | 怎么处理 | |---|---| | 盖章横幅 / 大标题 / 填报单位 / 空行占掉开头好几行,真表头在下面 | 在开头 7 行里定位真表头,其上的垃圾整体丢弃;`1 2 3…` 的编号行不进列名 | | 多层合并表头(级联) | 合并单元格向下/向右填充,各级用 `/` 连接,如 `用工主体信息/企业名称` | | 表格标注 100 万行、实际只有几千行有内容 | 只扫描真正有值的行,不再被"有格式没值"的空白拖垮(原来要 42 秒,现 15 秒,剩下是文件加载耗时);体检提示"其余是空白,已忽略" | | 主表很远的地方有零星残留数据 | 默认**不导入**,行号和内容列在体检里让你检查;体量相当的后续块则并入并提示"可能是两张表拼在一起" | | 表尾有“合计 / 小计 / 总计” | 结合标签、位置、公式和真人信号识别;导入前列出行号让用户确认,确认后不作为明细入库,但在体检中留档 | | 几乎是空的行(如只有一个重复的名字) | 体检按内容分组提示:"有 50 行除了「张三」外全是空的" | | 完全重复的行(忽略序号) / 同一身份证对应不同姓名 | 体检提示,不自动删除 | | 表头没认对(有数据却没列名) | 体检提示,可在导入页手动指定表头行数 | | 身份证 15/17/20 位、校验位错 | 自动修复并标记 `repaired`;修不了进待修队列,人工处理 | | 日期是 Excel 序列号或 `1962.7.20` 之类文本 | 统一成 ISO(精度不足存 `YYYY-MM`) | | 值里混提示文字(`残疾证号:452227…`) | 按映射声明的 cleaner 剥离 | | `.xls` 实际是网页格式 / `.xlsx` 被改了扩展名 | 按文件头识别真实格式;网页伪装的给出"另存为 .xlsx"的指引 | ## 技术栈 Python 3.11 + Streamlit + Pandas + openpyxl + xlrd(读 `.xls`)+ SQLite + [SiliconFlow API](https://siliconflow.cn)(默认 `deepseek-ai/DeepSeek-V3.2`,可在设置页更换) ## 快速开始 **使用(发行包)** ```bat 双击 启动.bat # 内置运行环境,无需安装 Python ``` 电脑本机访问 `http://localhost:8501`,手机同一局域网访问 `http://<电脑IP>:8501`。 首次运行在「设置」页(或 `乡亲录-数据/.env`)配置 `SILICONFLOW_API_KEY`。程序与数据分两个文件夹存放,升级只覆盖程序文件夹,**数据库和 `.env` 不会被动**。 **使用(macOS)** ```bash 双击 启动.command ``` 第一次双击会做三件事:找 Python(没有就打开官方下载页,装 3.11+ 即可)→ 装运行环境 (联网 1-3 分钟,之后不再重复)→ 查 Gitee 有没有新版(有就自动更新,没有就直接把网页 拉起来,浏览器会自动打开)。**之后每次双击都是「查更新 → 打开网页」**。 - 刚下载的压缩包解压后,双击可能会被 macOS 拦住(来自身份不明的开发者): **右键 → 打开 → 仍要打开**,只需一次。 - 如果双击没反应(zip 会丢掉执行权限):右键 → 打开方式 → 终端。 - 再双击一次不会开出第二个程序,而是直接把已开着的网页打开。 - 窗口里会打印这台电脑的局域网地址和「手机怎么打开」三步:手机连同一个 Wi-Fi, 浏览器里输入 `http://<那串地址>:8501` 即可;第一次可能弹防火墙提示,点「允许」。 - 数据在程序文件夹的 `data/` 里,更新不会动它;关掉终端窗口就是停止程序。 **开发** ```bat pip install -r requirements.txt streamlit run app.py --server.address 0.0.0.0 --server.port 8501 ``` ## 目录 ``` app.py 入口:页面路由(只做路由,逻辑全在 src/) launcher.py 启动器(升级检查、横幅、起服务) 启动.bat / 启动.command 两个平台的双击入口 src/ excel_parser 解析:表头定位 / 多级展平 / 合并单元格 / 指纹 / .xls 支持 / 孤立块识别 cleaner 清洗:身份证 / 日期 / 电话 / 垃圾行判定 quality 数据体检:空白膨胀 / 孤立行 / 零星行 / 重复行 / 证名冲突 / 表头可疑 catalog JSON 来源行 + 数据目录 + 找数据检索 importer 导入管线:简化映射 / 分组 / 人员关联 / 事务写库 repair 错误行修复 searcher 人物检索(零 AI,只读) exporter 模板导出 text2sql 自然语言查数(只读 SELECT) ai_client 全仓库唯一出网的 AI 边界 rules_store 规则库:发给 AI 的措辞可改、可停用、可恢复默认 db / paths / oplog 建库 / 数据目录定位 / 部署日志(自动给证号电话打码) ui/ Streamlit 页面(薄层) theme / palette 视觉层:全局样式、页首卡片、空态卡片;配色单一色源 art/ 自绘比熊插画 + 狗狗照片(随 src/ 进发行包) sample_data/ 测试样例:input(各类原始表)、output(导出模板) data/ 运行时数据库(开发布局) dist/ 发行包构建脚本 ``` ## 测试 每个 `src/` 模块都可独立运行,且带离线自测(合成数据、零真实 PII、零出网): ```bat python -m src.excel_parser --selftest python -m src.quality --selftest python -m src.catalog --selftest python -m src.importer --selftest python -m src.repair --selftest python -m src.db --selftest ``` 也可对单个文件做只读预览(不写库):`python -m src.importer --file `;`python -m src.catalog --search 低保` 在已导入的库里找列。 ## 隐私与安全 - 数据全部在本机 SQLite,局域网访问;**身份证、电话、`.env` 不进 git**。 - 发给 AI 的内容:表头 + 打码后的样例值。出境前有 PII 终检,命中即拒发。 - Text2SQL 只读:`PRAGMA query_only`、仅 `SELECT/WITH`、单语句、自动加 `LIMIT`。 - 部署日志只记文件名与计数,证号/电话等数字串落盘前自动打码。 ## 当前状态 - 已完成“完整来源行 JSON + `group_id` + 人物关联”数据模型切换。 - 导出默认由 AI 自动建议名单依据、输出粒度和多表列来源;手工选择移入高级设置, 并支持合并多张表人物后按身份证去重。 - 导入、检索、目录、修复、导出、Text2SQL 和四类可编辑 AI 规则均已切换到新结构。 - `sample_data` 中 8 个输入工作簿和 3 个输出模板已通过解析回归;股东清册 2759 行干跑得到 701 个组、2729 个合法人物和 30 个待修角色。 - 当前不提供旧测试数据库迁移,首次使用需从原 Excel 重新导入。 - 技术架构见 [开发说明.md](开发说明.md),改造阶段见 [数据模型改造开发文档.md](数据模型改造开发文档.md),导出细节见 [导出工作流开发文档.md](导出工作流开发文档.md)。