Metadata-Version: 2.4
Name: baisitong
Version: 1.0.4
Summary: 社区百事通 —— 社区政策咨询智能助手(AI+社会治理):FastAPI + RAG 知识库 + 多轮对话 + 来源引用
Author: yangxuan
License: MIT
Project-URL: Homepage, https://pypi.org/project/baisitong/
Keywords: community,policy,rag,fastapi,ai-agent
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi==0.115.0
Requires-Dist: uvicorn==0.30.6
Requires-Dist: python-multipart==0.0.12
Requires-Dist: sqlalchemy==2.0.35
Requires-Dist: pymysql==1.1.1
Requires-Dist: cryptography==43.0.3
Requires-Dist: httpx==0.27.2
Requires-Dist: python-dotenv==1.0.1
Provides-Extra: dev
Requires-Dist: pytest==8.3.3; extra == "dev"
Dynamic: license-file

# 🏘️ 社区百事通(baisitong)

> 社区政策咨询智能助手 · AI + 社会治理
> RAG 知识库 + 多轮对话 + 来源引用 + SSE 流式输出,**零配置、可离线运行**

[![npm](https://img.shields.io/badge/npm-baisitong-blue)](https://www.npmjs.com/package/baisitong)
[![pypi](https://img.shields.io/badge/pypi-baisitong-green)](https://pypi.org/project/baisitong/)
[![tests](https://img.shields.io/badge/tests-49%20passed-brightgreen)](#测试)

---

## 一分钟跑起来

**方式 1:npm(任何装了 Python 3.9+ 的电脑)**

```bash
npx baisitong                 # 自动建 venv、装依赖、启动,打开 http://localhost:8080
npx baisitong --port 9000     # 自定义端口
```

**方式 2:pip 安装**

```bash
pip install baisitong -i https://mirrors.aliyun.com/pypi/simple/
baisitong                     # 或 python -m baisitong
```

**方式 3:源码运行**

```bash
./startup.sh          # Linux / macOS(Windows 用 startup.bat)
# 或手动:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python -m baisitong --port 8080
```

> **零配置即用**:默认 SQLite + 内置本地 AI 引擎(TF-IDF 检索 + 抽取式生成),
> 无需数据库、无需 API Key、无需联网。配置大模型 Key 后自动切换真模型,见[配置](#配置)。

## 功能特性

| 模块 | 说明 |
|------|------|
| 🔍 **RAG 政策问答** | 向量(TF-IDF/BGE)+ 关键词双路混合检索,答案附带 `[1][2]` 引用标注 |
| 📎 **来源溯源** | 每条回答展示政策文档标题 + 原文片段 + 相关度进度条,可展开 |
| 💬 **多轮对话** | 会话上下文保持,支持"费用是多少?"这类省略式追问(查询改写 + 同义词归一) |
| ⚡ **SSE 流式** | 逐字打字机输出;生成前先推送"检索预览",用户可感知 AI 在查资料 |
| 🛟 **无答案兜底** | 知识库外问题明确告知"未找到",并推荐热门问题,绝不编造 |
| 📚 **知识库管理** | 内置 5 份政策文档(垃圾分类/养犬/物业/停车/补贴),支持 txt/md 上传自动分块入库 |
| 📊 **运营看板** | 今日答疑数、满意度、热门问题统计 |
| 👍 **反馈闭环** | 点赞/点踩计入当日统计 |

## 系统架构

```
┌────────────────────────────────────────────────────────────┐
│              前端 原生 HTML/CSS/JS(无框架、无构建)          │
│   会话侧栏 · SSE流式聊天气泡 · 引用卡片(相关度条) · 热门问题  │
└──────────────────────┬─────────────────────────────────────┘
                       │ HTTP / SSE
┌──────────────────────▼─────────────────────────────────────┐
│                     接口层 routers/                         │
│  chat(SSE) · conversations · knowledge · questions        │
│  feedback · stats · health                                 │
├────────────────────────────────────────────────────────────┤
│                     逻辑层 services/                        │
│  rag(问答编排) · retriever(混合检索+查询改写)            │
│  embeddings(向量引擎) · llm(大模型/本地引擎)            │
│  documents(分块入库) · prompts(提示词模板)              │
├────────────────────────────────────────────────────────────┤
│                     数据层 models/ + database.py            │
│  SQLAlchemy ORM → SQLite(默认) / MySQL 8(可切换)        │
└────────────────────────────────────────────────────────────┘
         │                        │
   GLM / DeepSeek API       内置本地引擎(离线兜底)
   (配置 Key 后启用)        TF-IDF 检索 + 抽取式生成
```

**AI 双引擎设计**:LLM 与 Embedding 均为"远程 API / 本地引擎"双实现,统一接口。
未配置 Key 或远程调用失败时自动降级本地引擎,保证**演示永不中断**。

**RAG 管线**:`查询改写(多轮指代+同义词归一) → 向量检索 + 关键词检索 →
相对归一化加权融合(α=0.7) → 双路绝对下限兜底 → Prompt 组装 → 流式生成 → 引用后处理`

## API 一览

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/chat` | 问答(SSE 流式:`retrieval`/`token`/`suggestions`/`done`) |
| GET | `/api/conversations` | 会话列表 |
| GET/DELETE | `/api/conversations/{id}` | 会话详情 / 删除 |
| POST | `/api/knowledge/init` | 初始化预置知识库(`force` 重建) |
| POST | `/api/knowledge/upload` | 上传政策文档(自动分块+向量化) |
| GET | `/api/knowledge/documents` | 文档列表 |
| GET | `/api/knowledge/search?q=` | 手动检索(调试) |
| GET | `/api/questions/hot` | 热门问题 |
| POST | `/api/feedback` | 点赞/点踩 |
| GET | `/api/stats` | 运营统计 |
| GET | `/api/health` | 健康检查(运行模式) |
| GET | `/docs` | FastAPI 自动生成的 OpenAPI 文档 |

SSE 事件示例:

```
data: {"type":"retrieval","sources":[{"citation_num":1,"doc_title":"…","snippet":"…","score":0.92}]}
data: {"type":"token","content":"根据《杭州市"}
data: {"type":"done","message_id":42,"sources":[…]}
data: [DONE]
```

## 配置

复制 `.env.example` 为 `.env` 按需修改(全部留空 = 零配置本地模式):

```bash
# 切换真实大模型(OpenAI 兼容协议,二选一)
LLM_API_KEY=sk-xxx
LLM_BASE_URL=https://api.deepseek.com/v1        # 或 https://open.bigmodel.cn/api/paas/v4
LLM_MODEL=deepseek-chat                          # 或 glm-4-flash

# 切换真实向量化(可选,留空用内置 TF-IDF)
EMBED_API_KEY=xxx
EMBED_BASE_URL=https://open.bigmodel.cn/api/paas/v4
EMBED_MODEL=embedding-3

# 切换 MySQL 8(默认 SQLite)
DATABASE_URL=mysql+pymysql://root:pwd@localhost:3306/community_assistant
```

RAG 参数(`CHUNK_SIZE`/`RETRIEVAL_TOP_K`/`VECTOR_WEIGHT`/`SCORE_THRESHOLD` 等)
同样在 `.env` 中调整。

## 项目结构

```
baisitong/
├── baisitong/                # Python 包(发布到 PyPI)
│   ├── __main__.py           # CLI 入口(python -m baisitong)
│   ├── main.py               # FastAPI 装配 + 生命周期
│   ├── config.py             # 配置层(集中管理参数)
│   ├── database.py           # 数据层:engine/session/建表
│   ├── routers/              # 接口层:6 个路由模块
│   ├── services/             # 逻辑层:RAG/检索/LLM/分块/Prompt
│   ├── models/               # ORM:documents/conversations/questions/stats
│   ├── schemas/              # Pydantic DTO
│   ├── data/                 # 预置政策文档 ×5
│   └── static/               # 前端(index.html/css/js)
├── bin/cli.js                # npm 启动器(找 Python → venv → 装依赖 → 启动)
├── tests/                    # pytest 单元+集成测试(49 个用例)
├── sql/init.sql              # MySQL 8 建表 DDL(含 ngram 全文索引)
├── package.json              # npm 发布配置
├── pyproject.toml            # PyPI 发布配置
├── requirements.txt          # Python 依赖
├── startup.sh / startup.bat  # 一键启动
└── .env.example              # 环境变量模板
```

## 测试

```bash
pip install -r requirements-dev.txt
pytest tests/ -v        # 49 个用例:分块/检索融合/查询改写/引用提取/
                        # SSE问答/多轮追问/无答案兜底/远程降级/断线落库/
                        # 会话CRUD/反馈统计
```

测试全程离线(自动使用本地引擎 + 临时 SQLite),无外部依赖。

## 常见问题

**Q: 为什么检索引擎自己实现而不用 FAISS/ChromaDB?**
社区政策语料通常 < 1000 块,纯 Python 内积耗时 < 10ms;零外部依赖 = 零安装风险,
在任何受限网络/离线环境下都可靠运行(竞赛可靠性优先原则)。

**Q: 受限/断网环境怎么部署?**
提前在有网电脑下载离线包:

```bash
pip download baisitong -d pkgs/ -i https://mirrors.aliyun.com/pypi/simple/
pip download -r requirements.txt -d pkgs/ -i https://mirrors.aliyun.com/pypi/simple/
```

把 `pkgs/` 目录拷贝到目标机器后 `pip install --no-index --find-links=pkgs/ baisitong`,
全程无需联网。

## License

MIT
